diff --git a/benchmarks/kis_gradient_benchmark.cpp b/benchmarks/kis_gradient_benchmark.cpp index 8f42c81aec..6eda152143 100644 --- a/benchmarks/kis_gradient_benchmark.cpp +++ b/benchmarks/kis_gradient_benchmark.cpp @@ -1,91 +1,91 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2010 Cyrille Berger * * 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 #include #include "kis_benchmark_values.h" #include "kis_random_accessor_ng.h" #include #include #include #include #include "kis_gradient_benchmark.h" #include #include #include void KisGradientBenchmark::initTestCase() { m_colorSpace = KoColorSpaceRegistry::instance()->rgb8(); m_device = new KisPaintDevice(m_colorSpace); m_color = KoColor(m_colorSpace); m_color.fromQColor(QColor(0,0,0,0)); // default pixel m_device->fill( 0,0,GMP_IMAGE_WIDTH, GMP_IMAGE_HEIGHT,m_color.data() ); } void KisGradientBenchmark::benchmarkGradient() { KoColor fg(m_colorSpace); KoColor bg(m_colorSpace); fg.fromQColor(Qt::blue); bg.fromQColor(Qt::black); QBENCHMARK { QLinearGradient grad; grad.setColorAt(0, Qt::white); grad.setColorAt(1.0, Qt::red); - KoAbstractGradient* kograd = KoStopGradient::fromQGradient(&grad); + KoAbstractGradientSP kograd(KoStopGradient::fromQGradient(&grad)); Q_ASSERT(kograd); KisGradientPainter fillPainter(m_device); //setupPainter(&fillPainter); fillPainter.setGradient(kograd); fillPainter.beginTransaction(kundo2_noi18n("Gradient Fill")); //fillPainter.setProgress(updater->startSubtask()); fillPainter.setOpacity(OPACITY_OPAQUE_U8); // default fillPainter.setCompositeOp(COMPOSITE_OVER); fillPainter.setGradientShape(KisGradientPainter::GradientShapeBiLinear); fillPainter.paintGradient(QPointF(0,0), QPointF(3000,3000), KisGradientPainter::GradientRepeatNone, 1.0, false, 0, 0, GMP_IMAGE_WIDTH,GMP_IMAGE_HEIGHT); fillPainter.deleteTransaction(); } // uncomment this to see the output QImage out = m_device->convertToQImage(m_colorSpace->profile(),0,0,GMP_IMAGE_WIDTH,GMP_IMAGE_HEIGHT); out.save("fill_output.png"); } void KisGradientBenchmark::cleanupTestCase() { } QTEST_MAIN(KisGradientBenchmark) diff --git a/benchmarks/kis_low_memory_benchmark.cpp b/benchmarks/kis_low_memory_benchmark.cpp index affbd3e6d5..133498cddf 100644 --- a/benchmarks/kis_low_memory_benchmark.cpp +++ b/benchmarks/kis_low_memory_benchmark.cpp @@ -1,231 +1,231 @@ /* * Copyright (c) 2012 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_low_memory_benchmark.h" #include #include "kis_benchmark_values.h" #include #include #include #include #include #include #include "kis_paint_device.h" #include "kis_painter.h" #include #include #include #include "tiles3/kis_tile_data_store.h" #include "kis_surrogate_undo_adapter.h" #include "kis_image_config.h" #define LOAD_PRESET_OR_RETURN(preset, fileName) \ if(!preset->load()) { dbgKrita << "Preset" << fileName << "was NOT loaded properly. Done."; return; } \ else dbgKrita << "Loaded preset:" << fileName #define HUGE_IMAGE_SIZE 8000 /** * This benchmark runs a series of huge strokes on a canvas with a * particular configuration of the swapper/pooler and history * management. After the test is done you can visualize the results * with the GNU Octave. Please use kis_low_memory_show_report.m file * for that. */ void KisLowMemoryBenchmark::benchmarkWideArea(const QString presetFileName, const QRectF &rect, qreal vstep, int numCycles, bool createTransaction, int hardLimitMiB, int softLimitMiB, int poolLimitMiB, int index) { - KisPaintOpPresetSP preset = new KisPaintOpPreset(QString(FILES_DATA_DIR) + QDir::separator() + presetFileName); + KisPaintOpPresetSP preset(new KisPaintOpPreset(QString(FILES_DATA_DIR) + QDir::separator() + presetFileName)); LOAD_PRESET_OR_RETURN(preset, presetFileName); /** * Initialize image and painter */ const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, HUGE_IMAGE_SIZE, HUGE_IMAGE_SIZE, colorSpace, "stroke sample image"); KisLayerSP layer = new KisPaintLayer(image, "temporary for stroke sample", OPACITY_OPAQUE_U8, colorSpace); KisLayerSP layerExtra = new KisPaintLayer(image, "temporary for threading", OPACITY_OPAQUE_U8, colorSpace); image->addNode(layer, image->root()); image->addNode(layerExtra, image->root()); KisPainter *painter = new KisPainter(layer->paintDevice()); painter->setPaintColor(KoColor(Qt::black, colorSpace)); painter->setPaintOpPreset(preset, layer, image); /** * A simple adapter that will store all the transactions for us */ KisSurrogateUndoAdapter undoAdapter; /** * Reset configuration to the desired settings */ KisImageConfig config(false); qreal oldHardLimit = config.memoryHardLimitPercent(); qreal oldSoftLimit = config.memorySoftLimitPercent(); qreal oldPoolLimit = config.memoryPoolLimitPercent(); const qreal _MiB = 100.0 / KisImageConfig::totalRAM(); config.setMemoryHardLimitPercent(hardLimitMiB * _MiB); config.setMemorySoftLimitPercent(softLimitMiB * _MiB); config.setMemoryPoolLimitPercent(poolLimitMiB * _MiB); KisTileDataStore::instance()->testingRereadConfig(); /** * Create an empty the log file */ QString fileName; fileName = QString("log_%1_%2_%3_%4_%5.txt") .arg(createTransaction) .arg(hardLimitMiB) .arg(softLimitMiB) .arg(poolLimitMiB) .arg(index); QFile logFile(fileName); logFile.open(QFile::WriteOnly | QFile::Truncate); QTextStream logStream(&logFile); logStream.setFieldWidth(10); logStream.setFieldAlignment(QTextStream::AlignRight); /** * Start painting on the image */ QTime cycleTime; QTime lineTime; cycleTime.start(); lineTime.start(); qreal rectBottom = rect.y() + rect.height(); for (int i = 0; i < numCycles; i++) { cycleTime.restart(); QLineF line(rect.topLeft(), rect.topLeft() + QPointF(rect.width(), 0)); if (createTransaction) { painter->beginTransaction(); } KisDistanceInformation currentDistance; while(line.y1() < rectBottom) { lineTime.restart(); KisPaintInformation pi1(line.p1(), 0.0); KisPaintInformation pi2(line.p2(), 1.0); painter->paintLine(pi1, pi2, ¤tDistance); painter->device()->setDirty(painter->takeDirtyRegion()); logStream << "L 1" << i << lineTime.elapsed() << KisTileDataStore::instance()->numTilesInMemory() * 16 << KisTileDataStore::instance()->numTiles() * 16 << createTransaction << endl; line.translate(0, vstep); } painter->device()->setDirty(painter->takeDirtyRegion()); if (createTransaction) { painter->endTransaction(&undoAdapter); } // comment/uncomment to emulate user waiting after the stroke QTest::qSleep(1000); logStream << "C 2" << i << cycleTime.elapsed() << KisTileDataStore::instance()->numTilesInMemory() * 16 << KisTileDataStore::instance()->numTiles() * 16 << createTransaction << config.memoryHardLimitPercent() / _MiB << config.memorySoftLimitPercent() / _MiB << config.memoryPoolLimitPercent() / _MiB << endl; } config.setMemoryHardLimitPercent(oldHardLimit * _MiB); config.setMemorySoftLimitPercent(oldSoftLimit * _MiB); config.setMemoryPoolLimitPercent(oldPoolLimit * _MiB); delete painter; } void KisLowMemoryBenchmark::unlimitedMemoryNoHistoryNoPool() { QString presetFileName = "autobrush_300px.kpp"; // one cycle takes about 48 MiB of memory (total 960 MiB) QRectF rect(150,150,4000,4000); qreal step = 250; int numCycles = 20; benchmarkWideArea(presetFileName, rect, step, numCycles, false, 3000, 3000, 0, 0); } void KisLowMemoryBenchmark::unlimitedMemoryHistoryNoPool() { QString presetFileName = "autobrush_300px.kpp"; // one cycle takes about 48 MiB of memory (total 960 MiB) QRectF rect(150,150,4000,4000); qreal step = 250; int numCycles = 20; benchmarkWideArea(presetFileName, rect, step, numCycles, true, 3000, 3000, 0, 0); } void KisLowMemoryBenchmark::unlimitedMemoryHistoryPool50() { QString presetFileName = "autobrush_300px.kpp"; // one cycle takes about 48 MiB of memory (total 960 MiB) QRectF rect(150,150,4000,4000); qreal step = 250; int numCycles = 20; benchmarkWideArea(presetFileName, rect, step, numCycles, true, 3000, 3000, 50, 0); } void KisLowMemoryBenchmark::memory2000History100Pool500HugeBrush() { QString presetFileName = "BIG_TESTING.kpp"; // one cycle takes about 316 MiB of memory (total 3+ GiB) QRectF rect(150,150,7850,7850); qreal step = 250; int numCycles = 10; benchmarkWideArea(presetFileName, rect, step, numCycles, true, 2000, 600, 500, 0); } QTEST_MAIN(KisLowMemoryBenchmark) diff --git a/benchmarks/kis_stroke_benchmark.cpp b/benchmarks/kis_stroke_benchmark.cpp index 0d42f1eb41..4a77e7cedf 100644 --- a/benchmarks/kis_stroke_benchmark.cpp +++ b/benchmarks/kis_stroke_benchmark.cpp @@ -1,528 +1,528 @@ /* * Copyright (c) 2010 Lukáš Tvrdý lukast.dev@gmail.com * * 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 #if defined(_WIN32) || defined(_WIN64) #define srand48 srand inline double drand48() { return double(rand()) / RAND_MAX; } #endif #include #include "kis_stroke_benchmark.h" #include "kis_benchmark_values.h" #include "kis_paint_device.h" #include #include #include #include #include #include #include #include #define GMP_IMAGE_WIDTH 3274 #define GMP_IMAGE_HEIGHT 2067 #include #include //#define SAVE_OUTPUT static const int LINES = 20; const QString OUTPUT_FORMAT = ".png"; void KisStrokeBenchmark::initTestCase() { m_dataPath = QString(FILES_DATA_DIR) + QDir::separator(); m_outputPath = QString(FILES_OUTPUT_DIR) + QDir::separator(); m_colorSpace = KoColorSpaceRegistry::instance()->rgb8(); m_color = KoColor(m_colorSpace); int width = TEST_IMAGE_WIDTH; int height = TEST_IMAGE_HEIGHT; m_image = new KisImage(0, width, height, m_colorSpace, "stroke sample image"); m_layer = new KisPaintLayer(m_image, "temporary for stroke sample", OPACITY_OPAQUE_U8, m_colorSpace); m_painter = new KisPainter(m_layer->paintDevice()); m_painter->setPaintColor(KoColor(Qt::black, m_colorSpace)); // for bezier curve test initCurvePoints(width, height); // for the lines test initLines(width,height); } void KisStrokeBenchmark::init() { KoColor white(m_colorSpace); white.fromQColor(Qt::white); m_layer->paintDevice()->fill(0,0, m_image->width(), m_image->height(),white.data()); } void KisStrokeBenchmark::initCurvePoints(int width, int height) { QPointF p1(0 , 7.0 / 12.0 * height); QPointF p2(1.0 / 2.0 * width , 7.0 / 12.0 * height); QPointF p3(width - 4.0, height - 4.0); m_c1 = QPointF(1.0 / 4.0 * width, height - 2.0); m_c2 = QPointF(3.0 / 4.0 * width, 0); m_pi1 = KisPaintInformation(p1, 0.0); m_pi2 = KisPaintInformation(p2, 0.95); m_pi3 = KisPaintInformation(p3, 0.0); } void KisStrokeBenchmark::initLines(int width, int height) { srand(12345678); for (int i = 0; i < LINES; i++){ qreal sx = rand() / qreal(RAND_MAX - 1); qreal sy = rand() / qreal(RAND_MAX - 1); m_startPoints.append(QPointF(sx * width,sy * height)); qreal ex = rand() / qreal(RAND_MAX - 1); qreal ey = rand() / qreal(RAND_MAX - 1); m_endPoints.append(QPointF(ex * width,ey * height)); } } void KisStrokeBenchmark::cleanupTestCase() { delete m_painter; } void KisStrokeBenchmark::deformBrush() { QString presetFileName = "deform-default.kpp"; benchmarkStroke(presetFileName); } void KisStrokeBenchmark::deformBrushRL() { QString presetFileName = "deform-default.kpp"; benchmarkRandomLines(presetFileName); } void KisStrokeBenchmark::pixelbrush300px() { QString presetFileName = "autobrush_300px.kpp"; benchmarkStroke(presetFileName); } void KisStrokeBenchmark::pixelbrush300pxRL() { QString presetFileName = "autobrush_300px.kpp"; benchmarkRandomLines(presetFileName); } void KisStrokeBenchmark::sprayPixels() { QString presetFileName = "spray_wu_pixels1.kpp"; benchmarkStroke(presetFileName); } void KisStrokeBenchmark::sprayPixelsRL() { QString presetFileName = "spray_wu_pixels1.kpp"; benchmarkRandomLines(presetFileName); } void KisStrokeBenchmark::sprayTexture() { QString presetFileName = "spray_21_textures1.kpp"; benchmarkStroke(presetFileName); } void KisStrokeBenchmark::sprayTextureRL() { QString presetFileName = "spray_21_textures1.kpp"; benchmarkRandomLines(presetFileName); } void KisStrokeBenchmark::spray30px21particles() { QString presetFileName = "spray_30px21rasterParticles.kpp"; benchmarkStroke(presetFileName); } void KisStrokeBenchmark::spray30px21particlesRL() { QString presetFileName = "spray_30px21rasterParticles.kpp"; benchmarkRandomLines(presetFileName); } void KisStrokeBenchmark::sprayPencil() { QString presetFileName = "spray_scaled2rasterParticles.kpp"; benchmarkStroke(presetFileName); } void KisStrokeBenchmark::sprayPencilRL() { QString presetFileName = "spray_scaled2rasterParticles.kpp"; benchmarkRandomLines(presetFileName); } void KisStrokeBenchmark::softbrushDefault30() { QString presetFileName = "softbrush_30px.kpp"; benchmarkStroke(presetFileName); } void KisStrokeBenchmark::softbrushCircle30() { QString presetFileName = "softbrush_30px.kpp"; benchmarkCircle(presetFileName); } void KisStrokeBenchmark::softbrushDefault30RL() { QString presetFileName = "softbrush_30px.kpp"; benchmarkRandomLines(presetFileName);} void KisStrokeBenchmark::softbrushFullFeatures30() { QString presetFileName = "softbrush_30px_full.kpp"; benchmarkStroke(presetFileName); } void KisStrokeBenchmark::softbrushFullFeatures30RL() { QString presetFileName = "softbrush_30px_full.kpp"; benchmarkRandomLines(presetFileName); } void KisStrokeBenchmark::hairy30pxDefault() { QString presetFileName = "hairybrush_thesis30px1.kpp"; benchmarkStroke(presetFileName); } void KisStrokeBenchmark::hairy30pxDefaultRL() { QString presetFileName = "hairybrush_thesis30px1.kpp"; benchmarkRandomLines(presetFileName); } void KisStrokeBenchmark::hairy30pxAntiAlias() { QString presetFileName = "hairybrush_thesis30px_antialiasing1.kpp"; benchmarkStroke(presetFileName); } void KisStrokeBenchmark::hairy30pxAntiAliasRL() { QString presetFileName = "hairybrush_thesis30px_antialiasing1.kpp"; benchmarkRandomLines(presetFileName); } void KisStrokeBenchmark::hairy30px30density() { QString presetFileName = "hairybrush_thesis30px_density301.kpp"; benchmarkStroke(presetFileName); } void KisStrokeBenchmark::hairy30px30densityRL() { QString presetFileName = "hairybrush_thesis30px_density301.kpp"; benchmarkRandomLines(presetFileName); } void KisStrokeBenchmark::hairy30InkDepletion() { QString presetFileName = "hairy30inkDepletion1.kpp"; benchmarkStroke(presetFileName); } void KisStrokeBenchmark::hairy30InkDepletionRL() { QString presetFileName = "hairy30inkDepletion1.kpp"; benchmarkRandomLines(presetFileName); } void KisStrokeBenchmark::softbrushOpacity() { QString presetFileName = "softbrush_opacity1.kpp"; benchmarkLine(presetFileName); } void KisStrokeBenchmark::softbrushSoftness() { QString presetFileName = "softbrush_softness1.kpp"; benchmarkLine(presetFileName); } void KisStrokeBenchmark::dynabrush() { QString presetFileName = "dyna301.kpp"; benchmarkLine(presetFileName); } void KisStrokeBenchmark::dynabrushRL() { QString presetFileName = "dyna301.kpp"; benchmarkRandomLines(presetFileName); } void KisStrokeBenchmark::experimental() { QString presetFileName = "experimental.kpp"; benchmarkStroke(presetFileName); } void KisStrokeBenchmark::experimentalCircle() { QString presetFileName = "experimental.kpp"; benchmarkCircle(presetFileName); } void KisStrokeBenchmark::colorsmudge() { QString presetFileName = "colorsmudge.kpp"; benchmarkStroke(presetFileName); } void KisStrokeBenchmark::colorsmudgeRL() { QString presetFileName = "colorsmudge.kpp"; benchmarkStroke(presetFileName); } /* void KisStrokeBenchmark::predefinedBrush() { QString presetFileName = "deevad-slow-brush1.kpp"; benchmarkLine(presetFileName); } void KisStrokeBenchmark::predefinedBrushRL() { QString presetFileName = "deevad-slow-brush1.kpp"; KisPaintOpPresetSP preset = new KisPaintOpPreset(m_dataPath + presetFileName); preset->load(); preset->settings()->setNode(m_layer); m_painter->setPaintOpPreset(preset, m_image); sleep(3); QBENCHMARK{ for (int i = 0; i < LINES; i++){ KisPaintInformation pi1(m_startPoints[i], 0.0); KisPaintInformation pi2(m_endPoints[i], 1.0); m_painter->paintLine(pi1, pi2); } } //m_layer->paintDevice()->convertToQImage(0).save(m_outputPath + presetFileName + "_randomLines" + OUTPUT_FORMAT); } */ inline void KisStrokeBenchmark::benchmarkLine(QString presetFileName) { - KisPaintOpPresetSP preset = new KisPaintOpPreset(m_dataPath + presetFileName); + KisPaintOpPresetSP preset(new KisPaintOpPreset(m_dataPath + presetFileName)); preset->load(); m_painter->setPaintOpPreset(preset, m_layer, m_image); QPointF startPoint(0.10 * TEST_IMAGE_WIDTH, 0.5 * TEST_IMAGE_HEIGHT); QPointF endPoint(0.90 * TEST_IMAGE_WIDTH, 0.5 * TEST_IMAGE_HEIGHT); KisDistanceInformation currentDistance; KisPaintInformation pi1(startPoint, 0.0); KisPaintInformation pi2(endPoint, 1.0); QBENCHMARK{ m_painter->paintLine(pi1, pi2, ¤tDistance); } #ifdef SAVE_OUTPUT m_layer->paintDevice()->convertToQImage(0).save(m_outputPath + presetFileName + "_line" + OUTPUT_FORMAT); #endif } void KisStrokeBenchmark::benchmarkCircle(QString presetFileName) { dbgKrita << "(circle)preset : " << presetFileName; - KisPaintOpPresetSP preset = new KisPaintOpPreset(m_dataPath + presetFileName); + KisPaintOpPresetSP preset(new KisPaintOpPreset(m_dataPath + presetFileName)); if (!preset->load()){ dbgKrita << "Preset was not loaded"; return; } m_painter->setPaintOpPreset(preset, m_layer, m_image); QBENCHMARK{ qreal radius = 300; qreal randomOffset = 300 * 0.4; int rounds = 20; int steps = 20; qreal step = 1.0 / steps; QPointF center(m_image->width() * 0.5, m_image->height() * 0.5); QPointF first(center.x()+radius,center.y()); srand48(0); for (int k = 0; k < rounds; k++){ KisDistanceInformation currentDistance; m_painter->paintLine(center, first, ¤tDistance); QPointF prev = first; for (int i = 1; i < steps; i++) { qreal cx = cos(i * step * 2 * M_PI); qreal cy = sin(i * step * 2 * M_PI); cx *= (radius + drand48() * randomOffset); cy *= (radius + drand48() * randomOffset); cx += center.x(); cy += center.y(); m_painter->paintLine(prev, QPointF(cx,cy), ¤tDistance); prev = QPointF(cx,cy); } m_painter->paintLine(prev, first, ¤tDistance); } } #ifdef SAVE_OUTPUT m_layer->paintDevice()->convertToQImage(0).save(m_outputPath + presetFileName + "_circle" + OUTPUT_FORMAT); #endif } void KisStrokeBenchmark::benchmarkRandomLines(QString presetFileName) { - KisPaintOpPresetSP preset = new KisPaintOpPreset(m_dataPath + presetFileName); + KisPaintOpPresetSP preset(new KisPaintOpPreset(m_dataPath + presetFileName)); bool loadedOk = preset->load(); if (!loadedOk){ dbgKrita << "The preset was not loaded correctly. Done."; return; }else{ dbgKrita << "preset : " << presetFileName; } m_painter->setPaintOpPreset(preset, m_layer, m_image); QBENCHMARK{ KisDistanceInformation currentDistance; for (int i = 0; i < LINES; i++){ KisPaintInformation pi1(m_startPoints[i], 0.0); KisPaintInformation pi2(m_endPoints[i], 1.0); m_painter->paintLine(pi1, pi2, ¤tDistance); } } #ifdef SAVE_OUTPUT m_layer->paintDevice()->convertToQImage(0).save(m_outputPath + presetFileName + "_randomLines" + OUTPUT_FORMAT); #endif } void KisStrokeBenchmark::benchmarkStroke(QString presetFileName) { - KisPaintOpPresetSP preset = new KisPaintOpPreset(m_dataPath + presetFileName); + KisPaintOpPresetSP preset(new KisPaintOpPreset(m_dataPath + presetFileName)); bool loadedOk = preset->load(); if (!loadedOk){ dbgKrita << "The preset was not loaded correctly. Done."; return; } else { dbgKrita << "preset : " << presetFileName; } m_painter->setPaintOpPreset(preset, m_layer, m_image); QBENCHMARK{ KisDistanceInformation currentDistance; m_painter->paintBezierCurve(m_pi1, m_c1, m_c1, m_pi2, ¤tDistance); m_painter->paintBezierCurve(m_pi2, m_c2, m_c2, m_pi3, ¤tDistance); } #ifdef SAVE_OUTPUT dbgKrita << "Saving output " << m_outputPath + presetFileName + ".png"; m_layer->paintDevice()->convertToQImage(0).save(m_outputPath + presetFileName + OUTPUT_FORMAT); #endif } static const int COUNT = 1000000; void KisStrokeBenchmark::benchmarkRand48() { QBENCHMARK { for (int i = 0 ; i < COUNT; i++){ double result = drand48(); Q_UNUSED(result); } } } void KisStrokeBenchmark::benchmarkRand() { float j; QBENCHMARK{ for (int i = 0 ; i < COUNT; i++){ j = rand() / (float)RAND_MAX; } } Q_UNUSED(j); } void KisStrokeBenchmark::becnhmarkPresetCloning() { QString presetFileName = "spray_21_textures1.kpp"; - KisPaintOpPresetSP preset = new KisPaintOpPreset(m_dataPath + presetFileName); + KisPaintOpPresetSP preset(new KisPaintOpPreset(m_dataPath + presetFileName)); bool loadedOk = preset->load(); KIS_ASSERT_RECOVER_RETURN(loadedOk); KIS_ASSERT_RECOVER_RETURN(preset->settings()); QBENCHMARK { KisPaintOpPresetSP other = preset->clone(); other->settings()->setPaintOpOpacity(0.3); } } QTEST_MAIN(KisStrokeBenchmark) diff --git a/libs/brush/kis_abr_brush.cpp b/libs/brush/kis_abr_brush.cpp index aeb5c83fb5..84c3c14f16 100644 --- a/libs/brush/kis_abr_brush.cpp +++ b/libs/brush/kis_abr_brush.cpp @@ -1,118 +1,118 @@ /* * Copyright (c) 2010 Boudewijn Rempt * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2007 Eric Lamarque * * 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_abr_brush.h" #include "kis_abr_brush_collection.h" #include #include #include #include #include #include #include #include #include #include "kis_datamanager.h" #include "kis_paint_device.h" #include "kis_global.h" #include "kis_image.h" #define DEFAULT_SPACING 0.25 KisAbrBrush::KisAbrBrush(const QString& filename, KisAbrBrushCollection *parent) : KisScalingSizeBrush(filename) , m_parent(parent) { setBrushType(INVALID); setHasColor(false); setSpacing(DEFAULT_SPACING); } KisAbrBrush::KisAbrBrush(const KisAbrBrush& rhs) : KisScalingSizeBrush(rhs), m_parent(0) { // Warning! The brush became detached from the parent! } KisAbrBrush::KisAbrBrush(const KisAbrBrush& rhs, KisAbrBrushCollection *parent) : KisScalingSizeBrush(rhs), m_parent(parent) { } -KisBrush* KisAbrBrush::clone() const +KisBrushSP KisAbrBrush::clone() const { - return new KisAbrBrush(*this); + return KisBrushSP(new KisAbrBrush(*this)); } bool KisAbrBrush::load() { return true; } bool KisAbrBrush::loadFromDevice(QIODevice */*dev*/) { return true; } bool KisAbrBrush::save() { //Return true, otherwise the brush won't be added to the //resource server if the brush is loaded via import return true; } bool KisAbrBrush::saveToDevice(QIODevice* /*dev*/) const { return true; } void KisAbrBrush::setBrushTipImage(const QImage& image) { setValid(true); setBrushType(MASK); setHasColor(false); KisBrush::setBrushTipImage(image); } void KisAbrBrush::toXML(QDomDocument& d, QDomElement& e) const { e.setAttribute("name", name()); // legacy predefinedBrushToXML("abr_brush", e); KisBrush::toXML(d, e); } QString KisAbrBrush::defaultFileExtension() const { return QString(); } QImage KisAbrBrush::brushTipImage() const { if (KisBrush::brushTipImage().isNull() && m_parent) { m_parent->load(); } return KisBrush::brushTipImage(); } diff --git a/libs/brush/kis_abr_brush.h b/libs/brush/kis_abr_brush.h index 5625814f23..e145473c8d 100644 --- a/libs/brush/kis_abr_brush.h +++ b/libs/brush/kis_abr_brush.h @@ -1,77 +1,79 @@ /* * Copyright (c) 2010 Boudewijn Rempt * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2007 Eric Lamarque * * 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_ABR_BRUSH_ #define KIS_ABR_BRUSH_ #include #include #include #include #include #include "kritabrush_export.h" class KisQImagemask; class KisAbrBrushCollection; typedef KisSharedPtr KisQImagemaskSP; class QString; class QIODevice; class BRUSH_EXPORT KisAbrBrush : public KisScalingSizeBrush { public: /// Construct brush to load filename later as brush KisAbrBrush(const QString& filename, KisAbrBrushCollection *parent); KisAbrBrush(const KisAbrBrush& rhs); KisAbrBrush(const KisAbrBrush& rhs, KisAbrBrushCollection *parent); - KisBrush* clone() const override; + KisBrushSP clone() const override; bool load() override; bool loadFromDevice(QIODevice *dev) override; bool save() override; bool saveToDevice(QIODevice* dev) const override; /** * @return default file extension for saving the brush */ QString defaultFileExtension() const override; QImage brushTipImage() const override; friend class KisAbrBrushCollection; void setBrushTipImage(const QImage& image) override; void toXML(QDomDocument& d, QDomElement& e) const override; private: KisAbrBrushCollection *m_parent; }; +typedef QSharedPointer KisAbrBrushSP; + #endif // KIS_ABR_BRUSH_ diff --git a/libs/brush/kis_abr_brush_collection.cpp b/libs/brush/kis_abr_brush_collection.cpp index cf1a48404d..b9c5d73ec3 100644 --- a/libs/brush/kis_abr_brush_collection.cpp +++ b/libs/brush/kis_abr_brush_collection.cpp @@ -1,627 +1,627 @@ /* * Copyright (c) 2010 Boudewijn Rempt * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2007 Eric Lamarque * * 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 #include "kis_abr_brush_collection.h" #include "kis_abr_brush.h" #include #include #include #include #include #include #include #include #include #include #include struct AbrInfo { //big endian short version; short subversion; // count of the images (brushes) in the abr file short count; }; /// save the QImages as png files to directory image_tests static QImage convertToQImage(char * buffer, qint32 width, qint32 height) { // create 8-bit indexed image QImage img(width, height, QImage::Format_RGB32); int pos = 0; int value = 0; for (int y = 0; y < height; y++) { QRgb *pixel = reinterpret_cast(img.scanLine(y)); for (int x = 0; x < width; x++, pos++) { value = 255 - buffer[pos]; pixel[x] = qRgb(value, value , value); } } return img; } static qint32 rle_decode(QDataStream & abr, char *buffer, qint32 height) { qint32 n; char ptmp; char ch; int i, j, c; short *cscanline_len; char *data = buffer; // read compressed size foreach scanline cscanline_len = new short[ height ]; for (i = 0; i < height; i++) { // short abr >> cscanline_len[i]; } // unpack each scanline data for (i = 0; i < height; i++) { for (j = 0; j < cscanline_len[i];) { // char if (!abr.device()->getChar(&ptmp)) { break; } n = ptmp; j++; if (n >= 128) // force sign n -= 256; if (n < 0) { // copy the following char -n + 1 times if (n == -128) // it's a nop continue; n = -n + 1; // char if (!abr.device()->getChar(&ch)) { break; } j++; for (c = 0; c < n; c++, data++) { *data = ch; } } else { // read the following n + 1 chars (no compr) for (c = 0; c < n + 1; c++, j++, data++) { // char if (!abr.device()->getChar(data)) { break; } } } } } delete [] cscanline_len; return 0; } static QString abr_v1_brush_name(const QString filename, qint32 id) { QString result = filename; int pos = filename.lastIndexOf('.'); result.remove(pos, 4); QTextStream(&result) << "_" << id; return result; } static bool abr_supported_content(AbrInfo *abr_hdr) { switch (abr_hdr->version) { case 1: case 2: return true; break; case 6: if (abr_hdr->subversion == 1 || abr_hdr->subversion == 2) return true; break; } return false; } static bool abr_reach_8BIM_section(QDataStream & abr, const QString name) { char tag[4]; char tagname[5]; qint32 section_size = 0; int r; // find 8BIMname section while (!abr.atEnd()) { r = abr.readRawData(tag, 4); if (r != 4) { warnKrita << "Error: Cannot read 8BIM tag "; return false; } if (strncmp(tag, "8BIM", 4)) { warnKrita << "Error: Start tag not 8BIM but " << (int)tag[0] << (int)tag[1] << (int)tag[2] << (int)tag[3] << " at position " << abr.device()->pos(); return false; } r = abr.readRawData(tagname, 4); if (r != 4) { warnKrita << "Error: Cannot read 8BIM tag name"; return false; } tagname[4] = '\0'; QString s1 = QString::fromLatin1(tagname, 4); if (!s1.compare(name)) { return true; } // long abr >> section_size; abr.device()->seek(abr.device()->pos() + section_size); } return true; } static qint32 find_sample_count_v6(QDataStream & abr, AbrInfo *abr_info) { qint64 origin; qint32 sample_section_size; qint32 sample_section_end; qint32 samples = 0; qint32 data_start; qint32 brush_size; qint32 brush_end; if (!abr_supported_content(abr_info)) return 0; origin = abr.device()->pos(); if (!abr_reach_8BIM_section(abr, "samp")) { // reset to origin abr.device()->seek(origin); return 0; } // long abr >> sample_section_size; sample_section_end = sample_section_size + abr.device()->pos(); if(sample_section_end < 0 || sample_section_end > abr.device()->size()) return 0; data_start = abr.device()->pos(); while ((!abr.atEnd()) && (abr.device()->pos() < sample_section_end)) { // read long abr >> brush_size; brush_end = brush_size; // complement to 4 while (brush_end % 4 != 0) brush_end++; qint64 newPos = abr.device()->pos() + brush_end; if(newPos > 0 && newPos < abr.device()->size()) { abr.device()->seek(newPos); } else return 0; samples++; } // set stream to samples data abr.device()->seek(data_start); //dbgKrita <<"samples : "<< samples; return samples; } static bool abr_read_content(QDataStream & abr, AbrInfo *abr_hdr) { abr >> abr_hdr->version; abr_hdr->subversion = 0; abr_hdr->count = 0; switch (abr_hdr->version) { case 1: case 2: abr >> abr_hdr->count; break; case 6: abr >> abr_hdr->subversion; abr_hdr->count = find_sample_count_v6(abr, abr_hdr); break; default: // unknown versions break; } // next bytes in abr are samples data return true; } static QString abr_read_ucs2_text(QDataStream & abr) { quint32 name_size; quint32 buf_size; uint i; /* two-bytes characters encoded (UCS-2) * format: * long : size - number of characters in string * data : zero terminated UCS-2 string */ // long abr >> name_size; if (name_size == 0) { return QString(); } //buf_size = name_size * 2; buf_size = name_size; //name_ucs2 = (char*) malloc (buf_size * sizeof (char)); //name_ucs2 = new char[buf_size]; ushort * name_ucs2 = new ushort[buf_size]; for (i = 0; i < buf_size ; i++) { //* char*/ //abr >> name_ucs2[i]; // I will use ushort as that is input to fromUtf16 abr >> name_ucs2[i]; } QString name_utf8 = QString::fromUtf16(name_ucs2, buf_size); delete [] name_ucs2; return name_utf8; } quint32 KisAbrBrushCollection::abr_brush_load_v6(QDataStream & abr, AbrInfo *abr_hdr, const QString filename, qint32 image_ID, qint32 id) { Q_UNUSED(image_ID); qint32 brush_size = 0; qint32 brush_end = 0; qint32 next_brush = 0; qint32 top, left, bottom, right; top = left = bottom = right = 0; short depth; char compression; qint32 width = 0; qint32 height = 0; qint32 size = 0; qint32 layer_ID = -1; char *buffer; abr >> brush_size; brush_end = brush_size; // complement to 4 while (brush_end % 4 != 0) { brush_end++; } next_brush = abr.device()->pos() + brush_end; // discard key abr.device()->seek(abr.device()->pos() + 37); if (abr_hdr->subversion == 1) // discard short coordinates and unknown short abr.device()->seek(abr.device()->pos() + 10); else // discard unknown bytes abr.device()->seek(abr.device()->pos() + 264); // long abr >> top; abr >> left; abr >> bottom; abr >> right; // short abr >> depth; // char abr.device()->getChar(&compression); width = right - left; height = bottom - top; size = width * (depth >> 3) * height; // remove .abr and add some id, so something like test.abr -> test_12345 QString name = abr_v1_brush_name(filename, id); buffer = (char*)malloc(size); // data decoding if (!compression) { // not compressed - read raw bytes as brush data //fread (buffer, size, 1, abr); abr.readRawData(buffer, size); } else { rle_decode(abr, buffer, height); } if (width < quint16_MAX && height < quint16_MAX) { // filename - filename of the file , e.g. test.abr // name - test_number_of_the_brush, e.g test_1, test_2 - KisAbrBrush* abrBrush = 0; + KisAbrBrushSP abrBrush; if (m_abrBrushes.contains(name)) { abrBrush = m_abrBrushes[name]; } else { - abrBrush = new KisAbrBrush(name, this); + abrBrush = KisAbrBrushSP(new KisAbrBrush(name, this)); abrBrush->setMD5(md5()); } abrBrush->setBrushTipImage(convertToQImage(buffer, width, height)); // XXX: call extra setters on abrBrush for other options of ABR brushes abrBrush->setValid(true); abrBrush->setName(name); m_abrBrushes[name] = abrBrush; } free(buffer); abr.device()->seek(next_brush); layer_ID = id; return layer_ID; } qint32 KisAbrBrushCollection::abr_brush_load_v12(QDataStream & abr, AbrInfo *abr_hdr, const QString filename, qint32 image_ID, qint32 id) { Q_UNUSED(image_ID); short brush_type; qint32 brush_size; qint32 next_brush; qint32 top, left, bottom, right; qint16 depth; char compression; QString name; qint32 width, height; qint32 size; qint32 layer_ID = -1; char *buffer; // short abr >> brush_type; // long abr >> brush_size; next_brush = abr.device()->pos() + brush_size; if (brush_type == 1) { // computed brush // FIXME: support it! warnKrita << "WARNING: computed brush unsupported, skipping."; abr.device()->seek(abr.device()->pos() + next_brush); // TODO: test also this one abr.skipRawData(next_brush); } else if (brush_type == 2) { // sampled brush // discard 4 misc bytes and 2 spacing bytes abr.device()->seek(abr.device()->pos() + 6); if (abr_hdr->version == 2) name = abr_read_ucs2_text(abr); if (name.isNull()) { name = abr_v1_brush_name(filename, id); } // discard 1 byte for antialiasing and 4 x short for short bounds abr.device()->seek(abr.device()->pos() + 9); // long abr >> top; abr >> left; abr >> bottom; abr >> right; // short abr >> depth; // char abr.device()->getChar(&compression); width = right - left; height = bottom - top; size = width * (depth >> 3) * height; /* FIXME: support wide brushes */ if (height > 16384) { warnKrita << "WARNING: wide brushes not supported"; abr.device()->seek(next_brush); } else { buffer = (char*)malloc(size); if (!compression) { // not compressed - read raw bytes as brush data abr.readRawData(buffer, size); } else { rle_decode(abr, buffer, height); } - KisAbrBrush* abrBrush = 0; + KisAbrBrushSP abrBrush; if (m_abrBrushes.contains(name)) { abrBrush = m_abrBrushes[name]; } else { - abrBrush = new KisAbrBrush(name, this); + abrBrush = KisAbrBrushSP(new KisAbrBrush(name, this)); abrBrush->setMD5(md5()); } abrBrush->setBrushTipImage(convertToQImage(buffer, width, height)); // XXX: call extra setters on abrBrush for other options of ABR brushes free (buffer); abrBrush->setValid(true); abrBrush->setName(name); m_abrBrushes[name] = abrBrush; layer_ID = 1; } } else { warnKrita << "Unknown ABR brush type, skipping."; abr.device()->seek(next_brush); } return layer_ID; } qint32 KisAbrBrushCollection::abr_brush_load(QDataStream & abr, AbrInfo *abr_hdr, const QString filename, qint32 image_ID, qint32 id) { qint32 layer_ID = -1; switch (abr_hdr->version) { case 1: // fall through, version 1 and 2 are compatible case 2: layer_ID = abr_brush_load_v12(abr, abr_hdr, filename, image_ID, id); break; case 6: layer_ID = abr_brush_load_v6(abr, abr_hdr, filename, image_ID, id); break; } return layer_ID; } KisAbrBrushCollection::KisAbrBrushCollection(const QString& filename) : KisScalingSizeBrush(filename) { } KisAbrBrushCollection::KisAbrBrushCollection(const KisAbrBrushCollection& rhs) : KisScalingSizeBrush(rhs) { for (auto it = rhs.m_abrBrushes.begin(); it != rhs.m_abrBrushes.end(); ++it) { - m_abrBrushes.insert(it.key(), new KisAbrBrush(*it.value(), this)); + m_abrBrushes.insert(it.key(), KisAbrBrushSP(new KisAbrBrush(*it.value(), this))); } } -KisBrush* KisAbrBrushCollection::clone() const +KisBrushSP KisAbrBrushCollection::clone() const { - return new KisAbrBrushCollection(*this); + return KisBrushSP(new KisAbrBrushCollection(*this)); } bool KisAbrBrushCollection::load() { QFile file(filename()); // check if the file is open correctly if (!file.open(QIODevice::ReadOnly)) { warnKrita << "Can't open file " << filename(); return false; } bool res = loadFromDevice(&file); file.close(); return res; } bool KisAbrBrushCollection::loadFromDevice(QIODevice *dev) { AbrInfo abr_hdr; qint32 image_ID; int i; qint32 layer_ID; QByteArray ba = dev->readAll(); QBuffer buf(&ba); buf.open(QIODevice::ReadOnly); QDataStream abr(&buf); if (!abr_read_content(abr, &abr_hdr)) { warnKrita << "Error: cannot parse ABR file: " << filename(); return false; } if (!abr_supported_content(&abr_hdr)) { warnKrita << "ERROR: unable to decode abr format version " << abr_hdr.version << "(subver " << abr_hdr.subversion << ")"; return false; } if (abr_hdr.count == 0) { errKrita << "ERROR: no sample brush found in " << filename(); return false; } image_ID = 123456; for (i = 0; i < abr_hdr.count; i++) { layer_ID = abr_brush_load(abr, &abr_hdr, shortFilename(), image_ID, i + 1); if (layer_ID == -1) { warnKrita << "Warning: problem loading brush #" << i << " in " << filename(); } } return true; } bool KisAbrBrushCollection::save() { return false; } bool KisAbrBrushCollection::saveToDevice(QIODevice */*dev*/) const { return false; } QImage KisAbrBrushCollection::image() const { return QImage(); } void KisAbrBrushCollection::toXML(QDomDocument& d, QDomElement& e) const { Q_UNUSED(d); Q_UNUSED(e); // Do nothing... } QString KisAbrBrushCollection::defaultFileExtension() const { return QString(".abr"); } diff --git a/libs/brush/kis_abr_brush_collection.h b/libs/brush/kis_abr_brush_collection.h index 4b18d19ba4..33332cb866 100644 --- a/libs/brush/kis_abr_brush_collection.h +++ b/libs/brush/kis_abr_brush_collection.h @@ -1,93 +1,95 @@ /* * Copyright (c) 2010 Boudewijn Rempt * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2007 Eric Lamarque * * 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_ABR_BRUSH_COLLECTION_H #define KIS_ABR_BRUSH_COLLECTION_H #include #include #include #include #include #include #include #include #include +#include + class QString; class QIODevice; -class KisAbrBrush; + struct AbrInfo; /** * load a collection of brushes from an abr file */ class BRUSH_EXPORT KisAbrBrushCollection : public KisScalingSizeBrush { protected: public: /// Construct brush to load filename later as brush KisAbrBrushCollection(const QString& filename); - KisBrush* clone() const override; + KisBrushSP clone() const override; ~KisAbrBrushCollection() override {} bool load() override; bool loadFromDevice(QIODevice *dev) override; bool save() override; bool saveToDevice(QIODevice* dev) const override; /** * @return a preview of the brush */ virtual QImage image() const; /** * @return default file extension for saving the brush */ QString defaultFileExtension() const override; - QList brushes() { + QList brushes() { return m_abrBrushes.values(); } protected: KisAbrBrushCollection(const KisAbrBrushCollection& rhs); void toXML(QDomDocument& d, QDomElement& e) const override; private: qint32 abr_brush_load(QDataStream & abr, AbrInfo *abr_hdr, const QString filename, qint32 image_ID, qint32 id); qint32 abr_brush_load_v12(QDataStream & abr, AbrInfo *abr_hdr, const QString filename, qint32 image_ID, qint32 id); quint32 abr_brush_load_v6(QDataStream & abr, AbrInfo *abr_hdr, const QString filename, qint32 image_ID, qint32 id); - QMap m_abrBrushes; + QMap m_abrBrushes; }; #endif diff --git a/libs/brush/kis_auto_brush.cpp b/libs/brush/kis_auto_brush.cpp index a16407c20d..f0f559fd46 100644 --- a/libs/brush/kis_auto_brush.cpp +++ b/libs/brush/kis_auto_brush.cpp @@ -1,398 +1,398 @@ /* * Copyright (c) 2004,2007-2009 Cyrille Berger * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2012 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 //MSVC requires that Vc come first #include "kis_auto_brush.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(_WIN32) || defined(_WIN64) #include #define srand48 srand inline double drand48() { return double(rand()) / RAND_MAX; } #endif struct KisAutoBrush::Private { Private() : randomness(0), density(1.0), idealThreadCountCached(1) {} Private(const Private &rhs) : shape(rhs.shape->clone()), randomness(rhs.randomness), density(rhs.density), idealThreadCountCached(rhs.idealThreadCountCached) { } QScopedPointer shape; qreal randomness; qreal density; int idealThreadCountCached; }; KisAutoBrush::KisAutoBrush(KisMaskGenerator* as, qreal angle, qreal randomness, qreal density) : KisBrush(), d(new Private) { d->shape.reset(as); d->randomness = randomness; d->density = density; d->idealThreadCountCached = QThread::idealThreadCount(); setBrushType(MASK); setWidth(qMax(qreal(1.0), d->shape->width())); setHeight(qMax(qreal(1.0), d->shape->height())); QImage image = createBrushPreview(); setBrushTipImage(image); // Set angle here so brush tip image is generated unrotated setAngle(angle); image = createBrushPreview(); setImage(image); } KisAutoBrush::~KisAutoBrush() { } qreal KisAutoBrush::userEffectiveSize() const { return d->shape->diameter(); } void KisAutoBrush::setUserEffectiveSize(qreal value) { d->shape->setDiameter(value); } KisAutoBrush::KisAutoBrush(const KisAutoBrush& rhs) : KisBrush(rhs), d(new Private(*rhs.d)) { } -KisBrush* KisAutoBrush::clone() const +KisBrushSP KisAutoBrush::clone() const { - return new KisAutoBrush(*this); + return KisBrushSP(new KisAutoBrush(*this)); } /* It's difficult to predict the mask height when exaclty when there are * more than 2 spikes, so we return an upperbound instead. */ static KisDabShape lieAboutDabShape(KisDabShape const& shape) { return KisDabShape(shape.scale(), 1.0, shape.rotation()); } qint32 KisAutoBrush::maskHeight(KisDabShape const& shape, qreal subPixelX, qreal subPixelY, const KisPaintInformation& info) const { return KisBrush::maskHeight( lieAboutDabShape(shape), subPixelX, subPixelY, info); } qint32 KisAutoBrush::maskWidth(KisDabShape const& shape, qreal subPixelX, qreal subPixelY, const KisPaintInformation& info) const { return KisBrush::maskWidth( lieAboutDabShape(shape), subPixelX, subPixelY, info); } QSizeF KisAutoBrush::characteristicSize(KisDabShape const& shape) const { return KisBrush::characteristicSize(lieAboutDabShape(shape)); } inline void fillPixelOptimized_4bytes(quint8 *color, quint8 *buf, int size) { /** * This version of filling uses low granularity of data transfers * (32-bit chunks) and internal processor's parallelism. It reaches * 25% better performance in KisStrokeBenchmark in comparison to * per-pixel memcpy version (tested on Sandy Bridge). */ int block1 = size / 8; int block2 = size % 8; quint32 *src = reinterpret_cast(color); quint32 *dst = reinterpret_cast(buf); // check whether all buffers are 4 bytes aligned // (uncomment if experience some problems) // Q_ASSERT(((qint64)src & 3) == 0); // Q_ASSERT(((qint64)dst & 3) == 0); for (int i = 0; i < block1; i++) { *dst = *src; *(dst + 1) = *src; *(dst + 2) = *src; *(dst + 3) = *src; *(dst + 4) = *src; *(dst + 5) = *src; *(dst + 6) = *src; *(dst + 7) = *src; dst += 8; } for (int i = 0; i < block2; i++) { *dst = *src; dst++; } } inline void fillPixelOptimized_general(quint8 *color, quint8 *buf, int size, int pixelSize) { /** * This version uses internal processor's parallelism and gives * 20% better performance in KisStrokeBenchmark in comparison to * per-pixel memcpy version (tested on Sandy Bridge (+20%) and * on Merom (+10%)). */ int block1 = size / 8; int block2 = size % 8; for (int i = 0; i < block1; i++) { quint8 *d1 = buf; quint8 *d2 = buf + pixelSize; quint8 *d3 = buf + 2 * pixelSize; quint8 *d4 = buf + 3 * pixelSize; quint8 *d5 = buf + 4 * pixelSize; quint8 *d6 = buf + 5 * pixelSize; quint8 *d7 = buf + 6 * pixelSize; quint8 *d8 = buf + 7 * pixelSize; for (int j = 0; j < pixelSize; j++) { *(d1 + j) = color[j]; *(d2 + j) = color[j]; *(d3 + j) = color[j]; *(d4 + j) = color[j]; *(d5 + j) = color[j]; *(d6 + j) = color[j]; *(d7 + j) = color[j]; *(d8 + j) = color[j]; } buf += 8 * pixelSize; } for (int i = 0; i < block2; i++) { memcpy(buf, color, pixelSize); buf += pixelSize; } } void KisAutoBrush::generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst, KisBrush::ColoringInformation* coloringInformation, KisDabShape const& shape, const KisPaintInformation& info, double subPixelX , double subPixelY, qreal softnessFactor) const { Q_UNUSED(info); // Generate the paint device from the mask const KoColorSpace* cs = dst->colorSpace(); quint32 pixelSize = cs->pixelSize(); // mask dimension methods already includes KisBrush::angle() int dstWidth = maskWidth(shape, subPixelX, subPixelY, info); int dstHeight = maskHeight(shape, subPixelX, subPixelY, info); QPointF hotSpot = this->hotSpot(shape, info); // mask size and hotSpot function take the KisBrush rotation into account qreal angle = shape.rotation() + KisBrush::angle(); // if there's coloring information, we merely change the alpha: in that case, // the dab should be big enough! if (coloringInformation) { // new bounds. we don't care if there is some extra memory occcupied. dst->setRect(QRect(0, 0, dstWidth, dstHeight)); dst->lazyGrowBufferWithoutInitialization(); } else { KIS_SAFE_ASSERT_RECOVER_RETURN(dst->bounds().width() >= dstWidth && dst->bounds().height() >= dstHeight); } quint8* dabPointer = dst->data(); quint8* color = 0; if (coloringInformation) { if (dynamic_cast(coloringInformation)) { color = const_cast(coloringInformation->color()); } } double centerX = hotSpot.x() - 0.5 + subPixelX; double centerY = hotSpot.y() - 0.5 + subPixelY; d->shape->setScale(shape.scaleX(), shape.scaleY()); d->shape->setSoftness(softnessFactor); if (coloringInformation) { if (color && pixelSize == 4) { fillPixelOptimized_4bytes(color, dabPointer, dstWidth * dstHeight); } else if (color) { fillPixelOptimized_general(color, dabPointer, dstWidth * dstHeight, pixelSize); } else { for (int y = 0; y < dstHeight; y++) { for (int x = 0; x < dstWidth; x++) { memcpy(dabPointer, coloringInformation->color(), pixelSize); coloringInformation->nextColumn(); dabPointer += pixelSize; } coloringInformation->nextRow(); } } } MaskProcessingData data(dst, cs, d->randomness, d->density, centerX, centerY, angle); KisBrushMaskApplicatorBase *applicator = d->shape->applicator(); applicator->initializeData(&data); int jobs = d->idealThreadCountCached; if (threadingAllowed() && dstHeight > 100 && jobs >= 4) { int splitter = dstHeight / jobs; QVector rects; for (int i = 0; i < jobs - 1; i++) { rects << QRect(0, i * splitter, dstWidth, splitter); } rects << QRect(0, (jobs - 1)*splitter, dstWidth, dstHeight - (jobs - 1)*splitter); OperatorWrapper wrapper(applicator); QtConcurrent::blockingMap(rects, wrapper); } else { QRect rect(0, 0, dstWidth, dstHeight); applicator->process(rect); } } void KisAutoBrush::toXML(QDomDocument& doc, QDomElement& e) const { QDomElement shapeElt = doc.createElement("MaskGenerator"); d->shape->toXML(doc, shapeElt); e.appendChild(shapeElt); e.setAttribute("type", "auto_brush"); e.setAttribute("spacing", QString::number(spacing())); e.setAttribute("useAutoSpacing", QString::number(autoSpacingActive())); e.setAttribute("autoSpacingCoeff", QString::number(autoSpacingCoeff())); e.setAttribute("angle", QString::number(KisBrush::angle())); e.setAttribute("randomness", QString::number(d->randomness)); e.setAttribute("density", QString::number(d->density)); KisBrush::toXML(doc, e); } QImage KisAutoBrush::createBrushPreview() { int width = maskWidth(KisDabShape(), 0.0, 0.0, KisPaintInformation()); int height = maskHeight(KisDabShape(), 0.0, 0.0, KisPaintInformation()); KisPaintInformation info(QPointF(width * 0.5, height * 0.5), 0.5, 0, 0, angle(), 0, 0, 0, 0); KisFixedPaintDeviceSP fdev = new KisFixedPaintDevice(KoColorSpaceRegistry::instance()->rgb8()); fdev->setRect(QRect(0, 0, width, height)); fdev->initialize(); mask(fdev, KoColor(Qt::black, fdev->colorSpace()), KisDabShape(), info); return fdev->convertToQImage(0); } const KisMaskGenerator* KisAutoBrush::maskGenerator() const { return d->shape.data(); } qreal KisAutoBrush::density() const { return d->density; } qreal KisAutoBrush::randomness() const { return d->randomness; } QPainterPath KisAutoBrush::outline() const { bool simpleOutline = (d->density < 1.0); if (simpleOutline) { QPainterPath path; QRectF brushBoundingbox(0, 0, width(), height()); if (maskGenerator()->type() == KisMaskGenerator::CIRCLE) { path.addEllipse(brushBoundingbox); } else { // if (maskGenerator()->type() == KisMaskGenerator::RECTANGLE) path.addRect(brushBoundingbox); } return path; } return KisBrush::boundary()->path(); } void KisAutoBrush::lodLimitations(KisPaintopLodLimitations *l) const { KisBrush::lodLimitations(l); if (!qFuzzyCompare(density(), 1.0)) { l->limitations << KoID("auto-brush-density", i18nc("PaintOp instant preview limitation", "Brush Density recommended value 100.0")); } if (!qFuzzyCompare(randomness(), 0.0)) { l->limitations << KoID("auto-brush-randomness", i18nc("PaintOp instant preview limitation", "Brush Randomness recommended value 0.0")); } } diff --git a/libs/brush/kis_auto_brush.h b/libs/brush/kis_auto_brush.h index 0966f6eaa8..0250dd2b0e 100644 --- a/libs/brush/kis_auto_brush.h +++ b/libs/brush/kis_auto_brush.h @@ -1,103 +1,103 @@ /* * Copyright (c) 2004 Cyrille Berger * Copyright (c) 2010 Lukáš Tvrdý * * 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_AUTOBRUSH_RESOURCE_H_ #define _KIS_AUTOBRUSH_RESOURCE_H_ #include "kritabrush_export.h" #include "kis_brush.h" #include class KisMaskGenerator; /** * XXX: docs! */ class BRUSH_EXPORT KisAutoBrush : public KisBrush { public: KisAutoBrush(KisMaskGenerator* as, qreal angle, qreal randomness, qreal density = 1.0); KisAutoBrush(const KisAutoBrush& rhs); - KisBrush* clone() const override; + KisBrushSP clone() const override; ~KisAutoBrush() override; public: qreal userEffectiveSize() const override; void setUserEffectiveSize(qreal value) override; qint32 maskWidth(KisDabShape const& shape, qreal subPixelX, qreal subPixelY, const KisPaintInformation& info) const override; qint32 maskHeight(KisDabShape const& shape, qreal subPixelX, qreal subPixelY, const KisPaintInformation& info) const override; QSizeF characteristicSize(KisDabShape const&) const override; KisFixedPaintDeviceSP paintDevice(const KoColorSpace*, KisDabShape const&, const KisPaintInformation&, double = 0, double = 0) const override { return 0; // The autobrush does NOT support images! } void generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst, KisBrush::ColoringInformation* src, KisDabShape const&, const KisPaintInformation& info, double subPixelX = 0, double subPixelY = 0, qreal softnessFactor = DEFAULT_SOFTNESS_FACTOR) const override; QPainterPath outline() const override; public: bool load() override { return false; } bool loadFromDevice(QIODevice *) override { return false; } bool save() override { return false; } bool saveToDevice(QIODevice*) const override { return false; } void toXML(QDomDocument& , QDomElement&) const override; const KisMaskGenerator* maskGenerator() const; qreal randomness() const; qreal density() const; void lodLimitations(KisPaintopLodLimitations *l) const override; private: QImage createBrushPreview(); private: struct Private; const QScopedPointer d; }; #endif // _KIS_AUTOBRUSH_RESOURCE_H_ diff --git a/libs/brush/kis_auto_brush_factory.cpp b/libs/brush/kis_auto_brush_factory.cpp index ec0a697a13..266ae306e2 100644 --- a/libs/brush/kis_auto_brush_factory.cpp +++ b/libs/brush/kis_auto_brush_factory.cpp @@ -1,43 +1,43 @@ /* * Copyright (c) 2008 Boudewijn Rempt * Copyright (c) 2010-2011 Lukáš Tvrdý * * 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 //MSVC requires that Vc come first #include "kis_auto_brush_factory.h" #include #include "kis_auto_brush.h" #include "kis_mask_generator.h" #include KisBrushSP KisAutoBrushFactory::createBrush(const QDomElement &brushDefinition) { KisMaskGenerator* mask = KisMaskGenerator::fromXML(brushDefinition.firstChildElement("MaskGenerator")); double angle = KisDomUtils::toDouble(brushDefinition.attribute("angle", "0.0")); double randomness = KisDomUtils::toDouble(brushDefinition.attribute("randomness", "0.0")); qreal density = KisDomUtils::toDouble(brushDefinition.attribute("density", "1.0")); double spacing = KisDomUtils::toDouble(brushDefinition.attribute("spacing", "1.0")); bool useAutoSpacing = KisDomUtils::toInt(brushDefinition.attribute("useAutoSpacing", "0")); qreal autoSpacingCoeff = KisDomUtils::toDouble(brushDefinition.attribute("autoSpacingCoeff", "1.0")); - KisBrushSP brush = new KisAutoBrush(mask, angle, randomness, density); + KisBrushSP brush = KisBrushSP(new KisAutoBrush(mask, angle, randomness, density)); brush->setSpacing(spacing); brush->setAutoSpacing(useAutoSpacing, autoSpacingCoeff); return brush; } diff --git a/libs/brush/kis_brush.h b/libs/brush/kis_brush.h index 2814c86521..4a562bd799 100644 --- a/libs/brush/kis_brush.h +++ b/libs/brush/kis_brush.h @@ -1,397 +1,397 @@ /* * Copyright (c) 1999 Matthias Elter * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004 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. */ #ifndef KIS_BRUSH_ #define KIS_BRUSH_ #include #include #include #include #include #include class KisQImagemask; typedef KisSharedPtr KisQImagemaskSP; class QString; class KoColor; class KoColorSpace; class KisPaintInformation; class KisBoundary; class KisPaintopLodLimitations; enum enumBrushType { INVALID, MASK, IMAGE, PIPE_MASK, PIPE_IMAGE }; static const qreal DEFAULT_SOFTNESS_FACTOR = 1.0; class KisBrush; -typedef KisSharedPtr KisBrushSP; +typedef QSharedPointer KisBrushSP; /** * KisBrush is the base class for brush resources. A brush resource * defines one or more images that are used to potato-stamp along * the drawn path. The brush type defines how this brush is used -- * the important difference is between masks (which take the current * painting color) and images (which do not). It is up to the paintop * to make use of this feature. * * Brushes must be serializable to an xml representation and provide * a factory class that can recreate or retrieve the brush based on * this representation. * * XXX: This api is still a big mess -- it needs a good refactoring. * And the whole KoResource architecture is way over-designed. */ class BRUSH_EXPORT KisBrush : public KoResource, public KisShared { public: class ColoringInformation { public: virtual ~ColoringInformation(); virtual const quint8* color() const = 0; virtual void nextColumn() = 0; virtual void nextRow() = 0; }; protected: class PlainColoringInformation : public ColoringInformation { public: PlainColoringInformation(const quint8* color); ~PlainColoringInformation() override; const quint8* color() const override ; void nextColumn() override; void nextRow() override; private: const quint8* m_color; }; class PaintDeviceColoringInformation : public ColoringInformation { public: PaintDeviceColoringInformation(const KisPaintDeviceSP source, int width); ~PaintDeviceColoringInformation() override; const quint8* color() const override ; void nextColumn() override; void nextRow() override; private: const KisPaintDeviceSP m_source; KisHLineConstIteratorSP m_iterator; }; public: KisBrush(); KisBrush(const QString& filename); ~KisBrush() override; virtual qreal userEffectiveSize() const = 0; virtual void setUserEffectiveSize(qreal value) = 0; bool load() override { return false; } bool loadFromDevice(QIODevice *) override { return false; } bool save() override { return false; } bool saveToDevice(QIODevice* ) const override { return false; } /** * @brief brushImage the image the brush tip can paint with. Not all brush types have a single * image. * @return a valid QImage. */ virtual QImage brushTipImage() const; /** * Change the spacing of the brush. * @param spacing a spacing of 1.0 means that strokes will be separated from one time the size * of the brush. */ virtual void setSpacing(double spacing); /** * @return the spacing between two strokes for this brush */ double spacing() const; void setAutoSpacing(bool active, qreal coeff); bool autoSpacingActive() const; qreal autoSpacingCoeff() const; /** * @return the width (for scale == 1.0) */ qint32 width() const; /** * @return the height (for scale == 1.0) */ qint32 height() const; /** * @return the width of the mask for the given scale and angle */ virtual qint32 maskWidth(KisDabShape const&, qreal subPixelX, qreal subPixelY, const KisPaintInformation& info) const; /** * @return the height of the mask for the given scale and angle */ virtual qint32 maskHeight(KisDabShape const&, qreal subPixelX, qreal subPixelY, const KisPaintInformation& info) const; /** * @return the logical size of the brush, that is the size measured * in floating point value. * * This value should not be used for calculating future dab sizes * because it doesn't take any rounding into account. The only use * of this metric is calculation of brush-size derivatives like * hotspots and spacing. */ virtual QSizeF characteristicSize(KisDabShape const&) const; /** * @return the angle of the mask adding the given angle */ double maskAngle(double angle = 0) const; /** * @return the index of the brush * if the brush consists of multiple images */ virtual quint32 brushIndex(const KisPaintInformation& info) const; /** * The brush type defines how the brush is used. */ virtual enumBrushType brushType() const; QPointF hotSpot(KisDabShape const&, const KisPaintInformation& info) const; /** * Returns true if this brush can return something useful for the info. This is used * by Pipe Brushes that can't paint sometimes **/ virtual bool canPaintFor(const KisPaintInformation& /*info*/); /** * Is called by the paint op when a paintop starts a stroke. The * point is that we store brushes a server while the paint ops are * are recreated all the time. Is means that upon a stroke start * the brushes may need to clear its state. */ virtual void notifyStrokeStarted(); /** * Is called by the cache, when cache hit has happened. * Having got this notification the brush can update the counters * of dabs, generate some new random values if needed. * * * NOTE: one should use **either** notifyCachedDabPainted() or prepareForSeqNo() * * Currently, this is used by pipe'd brushes to implement * incremental and random parasites */ virtual void notifyCachedDabPainted(const KisPaintInformation& info); /** * Is called by the multithreaded queue to prepare a specific brush * tip for the particular seqNo. * * NOTE: one should use **either** notifyCachedDabPainted() or prepareForSeqNo() * * Currently, this is used by pipe'd brushes to implement * incremental and random parasites */ virtual void prepareForSeqNo(const KisPaintInformation& info, int seqNo); /** * Notify the brush if it can use QtConcurrent's threading capabilities in its * internal routines. By default it is allowed, but some paintops (who do their * own multithreading) may ask the brush to avoid internal threading. */ void setThreadingAllowed(bool value); /** * \see setThreadingAllowed() for details */ bool threadingAllowed() const; /** * Return a fixed paint device that contains a correctly scaled image dab. */ virtual KisFixedPaintDeviceSP paintDevice(const KoColorSpace * colorSpace, KisDabShape const&, const KisPaintInformation& info, double subPixelX = 0, double subPixelY = 0) const; /** * clear dst fill it with a mask colored with KoColor */ void mask(KisFixedPaintDeviceSP dst, const KoColor& color, KisDabShape const& shape, const KisPaintInformation& info, double subPixelX = 0, double subPixelY = 0, qreal softnessFactor = DEFAULT_SOFTNESS_FACTOR) const; /** * clear dst and fill it with a mask colored with the corresponding colors of src */ void mask(KisFixedPaintDeviceSP dst, const KisPaintDeviceSP src, KisDabShape const& shape, const KisPaintInformation& info, double subPixelX = 0, double subPixelY = 0, qreal softnessFactor = DEFAULT_SOFTNESS_FACTOR) const; virtual bool hasColor() const; /** * Create a mask and either mask dst (that is, change all alpha values of the * existing pixels to those of the mask) or, if coloringInfo is present, clear * dst and fill dst with pixels according to coloringInfo, masked according to the * generated mask. * * @param dst the destination that will be draw on the image, and this function * will edit its alpha channel * @param coloringInfo coloring information that will be copied on the dab, it can be null * @param scale a scale applied on the alpha mask * @param angle a rotation applied on the alpha mask * @param info the painting information (this is only and should only be used by * KisImagePipeBrush and only to be backward compatible with the Gimp, * KisImagePipeBrush is ignoring scale and angle information) * @param subPixelX sub position of the brush (contained between 0.0 and 1.0) * @param subPixelY sub position of the brush (contained between 0.0 and 1.0) * * @return a mask computed from the grey-level values of the * pixels in the brush. */ virtual void generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst, ColoringInformation* coloringInfo, KisDabShape const&, const KisPaintInformation& info, double subPixelX = 0, double subPixelY = 0, qreal softnessFactor = DEFAULT_SOFTNESS_FACTOR) const; /** * Serialize this brush to XML. */ virtual void toXML(QDomDocument& , QDomElement&) const; static KisBrushSP fromXML(const QDomElement& element); virtual const KisBoundary* boundary() const; virtual QPainterPath outline() const; virtual void setScale(qreal _scale); qreal scale() const; virtual void setAngle(qreal _angle); qreal angle() const; void clearBrushPyramid(); virtual void lodLimitations(KisPaintopLodLimitations *l) const; - virtual KisBrush* clone() const = 0; + virtual KisBrushSP clone() const = 0; protected: KisBrush(const KisBrush& rhs); void setWidth(qint32 width); void setHeight(qint32 height); void setHotSpot(QPointF); /** * XXX */ virtual void setBrushType(enumBrushType type); virtual void setHasColor(bool hasColor); public: /** * The image is used to represent the brush in the gui, and may also, depending on the brush type * be used to define the actual brush instance. */ virtual void setBrushTipImage(const QImage& image); /** * Returns true if the brush has a bunch of pixels almost * fully transparent in the very center. If the brush is pierced, * then dulling mode may not work correctly due to empty samples. * * WARNING: this method is relatively expensive since it iterates * up to 100 pixels of the brush. */ bool isPiercedApprox() const; protected: void resetBoundary(); void predefinedBrushToXML(const QString &type, QDomElement& e) const; private: // Initialize our boundary void generateBoundary() const; struct Private; Private* const d; }; #endif // KIS_BRUSH_ diff --git a/libs/brush/kis_brush_server.cpp b/libs/brush/kis_brush_server.cpp index b204d774a5..c49eb17c92 100644 --- a/libs/brush/kis_brush_server.cpp +++ b/libs/brush/kis_brush_server.cpp @@ -1,147 +1,147 @@ /* * Copyright (c) 2008 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_brush_server.h" #include #include #include #include #include #include #include #include "kis_abr_brush.h" #include "kis_abr_brush_collection.h" #include "kis_gbr_brush.h" #include "kis_imagepipe_brush.h" #include "kis_png_brush.h" #include "kis_svg_brush.h" Q_GLOBAL_STATIC(KisBrushServer, s_instance) class BrushResourceServer : public KisBrushResourceServer { public: BrushResourceServer() : KisBrushResourceServer("brushes", "*.gbr:*.gih:*.abr:*.png:*.svg") { } ///Reimplemented bool importResourceFile(const QString& filename, bool fileCreation = true) override { QFileInfo fi(filename); if (fi.exists() == false) return false; if (fi.size() == 0) return false; if (fi.suffix().toLower() == "abr") { if (fileCreation) { QFile::copy(filename, saveLocation() + fi.fileName()); } QList collectionResources = createResources(filename); Q_FOREACH (KisBrushSP brush, collectionResources) { addResource(brush); } } else { return KisBrushResourceServer::importResourceFile(filename, fileCreation); } qApp->processEvents(QEventLoop::AllEvents); return true; } private: ///Reimplemented QList createResources(const QString & filename) override { QList brushes; QString fileExtension = QFileInfo(filename).suffix().toLower(); if (fileExtension == "abr") { KisAbrBrushCollection collection(filename); collection.load(); - Q_FOREACH (KisAbrBrush * abrBrush, collection.brushes()) { + Q_FOREACH (KisAbrBrushSP abrBrush, collection.brushes()) { // abrBrush->setBrushTipImage(QImage()); brushes.append(abrBrush); addTag(abrBrush, collection.filename()); } } else { brushes.append(createResource(filename)); } return brushes; } ///Reimplemented - KisBrushSP createResource(const QString & filename) override { - - QString fileExtension = QFileInfo(filename).suffix().toLower(); - - KisBrushSP brush; - - if (fileExtension == "gbr") { - brush = new KisGbrBrush(filename); - } - else if (fileExtension == "gih") { - brush = new KisImagePipeBrush(filename); - } - else if (fileExtension == "png") { - brush = new KisPngBrush(filename); - } - else if (fileExtension == "svg") { - brush = new KisSvgBrush(filename); - } - return brush; + KisBrushSP createResource(const QString & /*filename*/) override { + return 0; +// QString fileExtension = QFileInfo(filename).suffix().toLower(); + +// KisBrushSP brush; + +// if (fileExtension == "gbr") { +// brush = KisBrushSP(new KisGbrBrush(filename)); +// } +// else if (fileExtension == "gih") { +// brush = KisBrushSP(new KisImagePipeBrush(filename)); +// } +// else if (fileExtension == "png") { +// brush = KisBrushSP(new KisPngBrush(filename)); +// } +// else if (fileExtension == "svg") { +// brush = KisBrushSP(new KisSvgBrush(filename)); +// } +// return brush; } }; KisBrushServer::KisBrushServer() { m_brushServer = new BrushResourceServer(); m_brushServer->loadResources(KoResourceServerProvider::blacklistFileNames(m_brushServer->fileNames(), m_brushServer->blackListedFiles())); } KisBrushServer::~KisBrushServer() { delete m_brushServer; } KisBrushServer* KisBrushServer::instance() { return s_instance; } KisBrushResourceServer* KisBrushServer::brushServer() { return m_brushServer; } void KisBrushServer::slotRemoveBlacklistedResources() { m_brushServer->removeBlackListedFiles(); } diff --git a/libs/brush/kis_brush_server.h b/libs/brush/kis_brush_server.h index 4ce7b92092..eccb6f0ea2 100644 --- a/libs/brush/kis_brush_server.h +++ b/libs/brush/kis_brush_server.h @@ -1,60 +1,60 @@ /* * Copyright (c) 2008 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. */ #ifndef KIS_BRUSH_SERVER_H #define KIS_BRUSH_SERVER_H #include #include #include #include #include #include "kritabrush_export.h" #include "kis_brush.h" -typedef KoResourceServer > KisBrushResourceServer; -typedef KoResourceServerAdapter > KisBrushResourceServerAdapter; +typedef KoResourceServer KisBrushResourceServer; +typedef KoResourceServerAdapter KisBrushResourceServerAdapter; /** * */ class BRUSH_EXPORT KisBrushServer : public QObject { Q_OBJECT public: KisBrushServer(); ~KisBrushServer() override; KisBrushResourceServer* brushServer(); static KisBrushServer* instance(); public Q_SLOTS: void slotRemoveBlacklistedResources(); private: KisBrushServer(const KisBrushServer&); KisBrushServer operator=(const KisBrushServer&); KisBrushResourceServer* m_brushServer; }; #endif diff --git a/libs/brush/kis_brushes_pipe.h b/libs/brush/kis_brushes_pipe.h index 63f1cfd9e6..163e50af4e 100644 --- a/libs/brush/kis_brushes_pipe.h +++ b/libs/brush/kis_brushes_pipe.h @@ -1,182 +1,180 @@ /* * Copyright (c) 2012 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. */ #ifndef __KIS_BRUSHES_PIPE_H #define __KIS_BRUSHES_PIPE_H #include +#include template class KisBrushesPipe { public: KisBrushesPipe() { } KisBrushesPipe(const KisBrushesPipe &rhs) { - qDeleteAll(m_brushes); m_brushes.clear(); - Q_FOREACH (BrushType * brush, rhs.m_brushes) { - BrushType *clonedBrush = dynamic_cast(brush->clone()); + Q_FOREACH (QSharedPointer brush, rhs.m_brushes) { + KisBrushSP clonedBrush = brush->clone(); + QSharedPointer actualClonedBrush = clonedBrush.dynamicCast(); + m_brushes.append(actualClonedBrush ); KIS_ASSERT_RECOVER(clonedBrush) {continue;} - - m_brushes.append(clonedBrush); } } virtual ~KisBrushesPipe() { - qDeleteAll(m_brushes); } virtual void clear() { - qDeleteAll(m_brushes); m_brushes.clear(); } - BrushType* firstBrush() const { + QSharedPointer firstBrush() const { return m_brushes.first(); } - BrushType* lastBrush() const { + QSharedPointer lastBrush() const { return m_brushes.last(); } - BrushType* currentBrush(const KisPaintInformation& info) { + QSharedPointer currentBrush(const KisPaintInformation& info) { return !m_brushes.isEmpty() ? m_brushes.at(chooseNextBrush(info)) : 0; } int brushIndex(const KisPaintInformation& info) { return chooseNextBrush(info); } qint32 maskWidth(KisDabShape const& shape, double subPixelX, double subPixelY, const KisPaintInformation& info) { - BrushType *brush = currentBrush(info); + QSharedPointer brush = currentBrush(info); return brush ? brush->maskWidth(shape, subPixelX, subPixelY, info) : 0; } qint32 maskHeight(KisDabShape const& shape, double subPixelX, double subPixelY, const KisPaintInformation& info) { - BrushType *brush = currentBrush(info); + QSharedPointer brush = currentBrush(info); return brush ? brush->maskHeight(shape, subPixelX, subPixelY, info) : 0; } void setAngle(qreal angle) { - Q_FOREACH (BrushType * brush, m_brushes) { + Q_FOREACH (QSharedPointer brush, m_brushes) { brush->setAngle(angle); } } void setScale(qreal scale) { - Q_FOREACH (BrushType * brush, m_brushes) { + Q_FOREACH (QSharedPointer brush, m_brushes) { brush->setScale(scale); } } void setSpacing(double spacing) { - Q_FOREACH (BrushType * brush, m_brushes) { + Q_FOREACH (QSharedPointer brush, m_brushes) { brush->setSpacing(spacing); } } bool hasColor() const { - Q_FOREACH (BrushType * brush, m_brushes) { + Q_FOREACH (QSharedPointer brush, m_brushes) { if (brush->hasColor()) return true; } return false; } void notifyCachedDabPainted(const KisPaintInformation& info) { updateBrushIndexes(info, -1); } void prepareForSeqNo(const KisPaintInformation& info, int seqNo) { updateBrushIndexes(info, seqNo); } void generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst, KisBrush::ColoringInformation* coloringInformation, KisDabShape const& shape, const KisPaintInformation& info, double subPixelX , double subPixelY, qreal softnessFactor) { - BrushType *brush = currentBrush(info); + QSharedPointer brush = currentBrush(info); if (!brush) return; brush->generateMaskAndApplyMaskOrCreateDab(dst, coloringInformation, shape, info, subPixelX, subPixelY, softnessFactor); notifyCachedDabPainted(info); } KisFixedPaintDeviceSP paintDevice(const KoColorSpace * colorSpace, KisDabShape const& shape, const KisPaintInformation& info, double subPixelX, double subPixelY) { - BrushType *brush = currentBrush(info); + QSharedPointer brush = currentBrush(info); if (!brush) return 0; KisFixedPaintDeviceSP device = brush->paintDevice(colorSpace, shape, info, subPixelX, subPixelY); notifyCachedDabPainted(info); return device; } - QVector brushes() { + QVector> brushes() { return m_brushes; } void testingSelectNextBrush(const KisPaintInformation& info) { (void) chooseNextBrush(info); notifyCachedDabPainted(info); } /** * Is called by the paint op when a paintop starts a stroke. The * brushes are shared among different strokes, so sometimes the * brush should be reset. */ virtual void notifyStrokeStarted() = 0; protected: - void addBrush(BrushType *brush) { + void addBrush(QSharedPointer brush) { m_brushes.append(brush); } /** * Returns the index of the brush that corresponds to the current * values of \p info. This method is called *before* the dab is * actually painted. * * The method is const, so no internal counters of the brush should * change during its execution */ virtual int chooseNextBrush(const KisPaintInformation& info) = 0; /** * Updates internal counters of the brush *after* a dab has been * painted on the canvas. Some incremental switching of the brushes * may me implemented in this method. * * If \p seqNo is equal or greater than zero, then incremental iteration is * overridden by this seqNo value */ virtual void updateBrushIndexes(const KisPaintInformation& info, int seqNo) = 0; protected: - QVector m_brushes; + QVector> m_brushes; }; #endif /* __KIS_BRUSHES_PIPE_H */ diff --git a/libs/brush/kis_gbr_brush.cpp b/libs/brush/kis_gbr_brush.cpp index a8514ce8d6..2b5cfe25ad 100644 --- a/libs/brush/kis_gbr_brush.cpp +++ b/libs/brush/kis_gbr_brush.cpp @@ -1,506 +1,506 @@ /* * Copyright (c) 1999 Matthias Elter * Copyright (c) 2003 Patrick Julien * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2004 Adrian Page * Copyright (c) 2005 Bart Coppens * Copyright (c) 2007 Cyrille Berger * Copyright (c) 2010 Lukáš Tvrdý * * 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 #include #include "kis_gbr_brush.h" #include #include #include #include #include #include #include #include #include "kis_datamanager.h" #include "kis_paint_device.h" #include "kis_global.h" #include "kis_image.h" struct GimpBrushV1Header { quint32 header_size; /* header_size = sizeof (BrushHeader) + brush name */ quint32 version; /* brush file version # */ quint32 width; /* width of brush */ quint32 height; /* height of brush */ quint32 bytes; /* depth of brush in bytes */ }; /// All fields are in MSB on disk! struct GimpBrushHeader { quint32 header_size; /* header_size = sizeof (BrushHeader) + brush name */ quint32 version; /* brush file version # */ quint32 width; /* width of brush */ quint32 height; /* height of brush */ quint32 bytes; /* depth of brush in bytes */ /* The following are only defined in version 2 */ quint32 magic_number; /* GIMP brush magic number */ quint32 spacing; /* brush spacing as % of width & height, 0 - 1000 */ }; // Needed, or the GIMP won't open it! quint32 const GimpV2BrushMagic = ('G' << 24) + ('I' << 16) + ('M' << 8) + ('P' << 0); struct KisGbrBrush::Private { QByteArray data; bool ownData; /* seems to indicate that @ref data is owned by the brush, but in Qt4.x this is already guaranteed... so in reality it seems more to indicate whether the data is loaded from file (ownData = true) or memory (ownData = false) */ bool useColorAsMask; quint32 header_size; /* header_size = sizeof (BrushHeader) + brush name */ quint32 version; /* brush file version # */ quint32 bytes; /* depth of brush in bytes */ quint32 magic_number; /* GIMP brush magic number */ }; #define DEFAULT_SPACING 0.25 KisGbrBrush::KisGbrBrush(const QString& filename) : KisScalingSizeBrush(filename) , d(new Private) { d->ownData = true; d->useColorAsMask = false; setHasColor(false); setSpacing(DEFAULT_SPACING); } KisGbrBrush::KisGbrBrush(const QString& filename, const QByteArray& data, qint32 & dataPos) : KisScalingSizeBrush(filename) , d(new Private) { d->ownData = false; d->useColorAsMask = false; setHasColor(false); setSpacing(DEFAULT_SPACING); d->data = QByteArray::fromRawData(data.data() + dataPos, data.size() - dataPos); init(); d->data.clear(); dataPos += d->header_size + (width() * height() * d->bytes); } KisGbrBrush::KisGbrBrush(KisPaintDeviceSP image, int x, int y, int w, int h) : KisScalingSizeBrush() , d(new Private) { d->ownData = true; d->useColorAsMask = false; setHasColor(false); setSpacing(DEFAULT_SPACING); initFromPaintDev(image, x, y, w, h); } KisGbrBrush::KisGbrBrush(const QImage& image, const QString& name) : KisScalingSizeBrush() , d(new Private) { d->ownData = false; d->useColorAsMask = false; setHasColor(false); setSpacing(DEFAULT_SPACING); setBrushTipImage(image); setName(name); } KisGbrBrush::KisGbrBrush(const KisGbrBrush& rhs) : KisScalingSizeBrush(rhs) , d(new Private(*rhs.d)) { d->data = QByteArray(); } KisGbrBrush::~KisGbrBrush() { delete d; } bool KisGbrBrush::load() { QFile file(filename()); if (file.size() == 0) return false; file.open(QIODevice::ReadOnly); bool res = loadFromDevice(&file); file.close(); return res; } bool KisGbrBrush::loadFromDevice(QIODevice *dev) { if (d->ownData) { d->data = dev->readAll(); } return init(); } bool KisGbrBrush::init() { GimpBrushHeader bh; if (sizeof(GimpBrushHeader) > (uint)d->data.size()) { return false; } memcpy(&bh, d->data, sizeof(GimpBrushHeader)); bh.header_size = qFromBigEndian(bh.header_size); d->header_size = bh.header_size; bh.version = qFromBigEndian(bh.version); d->version = bh.version; bh.width = qFromBigEndian(bh.width); bh.height = qFromBigEndian(bh.height); bh.bytes = qFromBigEndian(bh.bytes); d->bytes = bh.bytes; bh.magic_number = qFromBigEndian(bh.magic_number); d->magic_number = bh.magic_number; if (bh.version == 1) { // No spacing in version 1 files so use Gimp default bh.spacing = static_cast(DEFAULT_SPACING * 100); } else { bh.spacing = qFromBigEndian(bh.spacing); if (bh.spacing > 1000) { return false; } } setSpacing(bh.spacing / 100.0); if (bh.header_size > (uint)d->data.size() || bh.header_size == 0) { return false; } QString name; if (bh.version == 1) { // Version 1 has no magic number or spacing, so the name // is at a different offset. Character encoding is undefined. const char *text = d->data.constData() + sizeof(GimpBrushV1Header); name = QString::fromLatin1(text, bh.header_size - sizeof(GimpBrushV1Header) - 1); } else { // ### Version = 3->cinepaint; may be float16 data! // Version >=2: UTF-8 encoding is used name = QString::fromUtf8(d->data.constData() + sizeof(GimpBrushHeader), bh.header_size - sizeof(GimpBrushHeader) - 1); } setName(name); if (bh.width == 0 || bh.height == 0) { return false; } QImage::Format imageFormat; if (bh.bytes == 1) { imageFormat = QImage::Format_Indexed8; } else { imageFormat = QImage::Format_ARGB32; } QImage image(QImage(bh.width, bh.height, imageFormat)); if (image.isNull()) { return false; } qint32 k = bh.header_size; if (bh.bytes == 1) { QVector table; for (int i = 0; i < 256; ++i) table.append(qRgb(i, i, i)); image.setColorTable(table); // Grayscale if (static_cast(k + bh.width * bh.height) > d->data.size()) { return false; } setHasColor(false); for (quint32 y = 0; y < bh.height; y++) { uchar *pixel = reinterpret_cast(image.scanLine(y)); for (quint32 x = 0; x < bh.width; x++, k++) { qint32 val = 255 - static_cast(d->data[k]); *pixel = val; ++pixel; } } } else if (bh.bytes == 4) { // RGBA if (static_cast(k + (bh.width * bh.height * 4)) > d->data.size()) { return false; } setHasColor(true); for (quint32 y = 0; y < bh.height; y++) { QRgb *pixel = reinterpret_cast(image.scanLine(y)); for (quint32 x = 0; x < bh.width; x++, k += 4) { *pixel = qRgba(d->data[k], d->data[k + 1], d->data[k + 2], d->data[k + 3]); ++pixel; } } } else { warnKrita << "WARNING: loading of GBR brushes with" << bh.bytes << "bytes per pixel is not supported"; return false; } setWidth(image.width()); setHeight(image.height()); if (d->ownData) { d->data.resize(0); // Save some memory, we're using enough of it as it is. } setValid(image.width() != 0 && image.height() != 0); setBrushTipImage(image); return true; } bool KisGbrBrush::initFromPaintDev(KisPaintDeviceSP image, int x, int y, int w, int h) { // Forcefully convert to RGBA8 // XXX profile and exposure? setBrushTipImage(image->convertToQImage(0, x, y, w, h, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags())); setName(image->objectName()); setHasColor(true); return true; } bool KisGbrBrush::save() { QFile file(filename()); file.open(QIODevice::WriteOnly | QIODevice::Truncate); bool ok = saveToDevice(&file); file.close(); return ok; } bool KisGbrBrush::saveToDevice(QIODevice* dev) const { GimpBrushHeader bh; QByteArray utf8Name = name().toUtf8(); // Names in v2 brushes are in UTF-8 char const* name = utf8Name.data(); int nameLength = qstrlen(name); int wrote; bh.header_size = qToBigEndian((quint32)sizeof(GimpBrushHeader) + nameLength + 1); bh.version = qToBigEndian((quint32)2); // Only RGBA8 data needed atm, no cinepaint stuff bh.width = qToBigEndian((quint32)width()); bh.height = qToBigEndian((quint32)height()); // Hardcoded, 4 bytes RGBA or 1 byte GREY if (!hasColor()) { bh.bytes = qToBigEndian((quint32)1); } else { bh.bytes = qToBigEndian((quint32)4); } bh.magic_number = qToBigEndian((quint32)GimpV2BrushMagic); bh.spacing = qToBigEndian(static_cast(spacing() * 100.0)); // Write header: first bh, then the name QByteArray bytes = QByteArray::fromRawData(reinterpret_cast(&bh), sizeof(GimpBrushHeader)); wrote = dev->write(bytes); bytes.clear(); if (wrote == -1) { return false; } wrote = dev->write(name, nameLength + 1); if (wrote == -1) { return false; } int k = 0; QImage image = brushTipImage(); if (!hasColor()) { bytes.resize(width() * height()); for (qint32 y = 0; y < height(); y++) { for (qint32 x = 0; x < width(); x++) { QRgb c = image.pixel(x, y); bytes[k++] = static_cast(255 - qRed(c)); // red == blue == green } } } else { bytes.resize(width() * height() * 4); for (qint32 y = 0; y < height(); y++) { for (qint32 x = 0; x < width(); x++) { // order for gimp brushes, v2 is: RGBA QRgb pixel = image.pixel(x, y); bytes[k++] = static_cast(qRed(pixel)); bytes[k++] = static_cast(qGreen(pixel)); bytes[k++] = static_cast(qBlue(pixel)); bytes[k++] = static_cast(qAlpha(pixel)); } } } wrote = dev->write(bytes); if (wrote == -1) { return false; } KoResource::saveToDevice(dev); return true; } QImage KisGbrBrush::brushTipImage() const { QImage image = KisBrush::brushTipImage(); if (hasColor() && useColorAsMask()) { for (int y = 0; y < image.height(); y++) { QRgb *pixel = reinterpret_cast(image.scanLine(y)); for (int x = 0; x < image.width(); x++) { QRgb c = pixel[x]; int a = qGray(c); pixel[x] = qRgba(a, a, a, qAlpha(c)); } } } return image; } enumBrushType KisGbrBrush::brushType() const { return !hasColor() || useColorAsMask() ? MASK : IMAGE; } void KisGbrBrush::setBrushType(enumBrushType type) { Q_UNUSED(type); qFatal("FATAL: protected member setBrushType has no meaning for KisGbrBrush"); } void KisGbrBrush::setBrushTipImage(const QImage& image) { KisBrush::setBrushTipImage(image); setValid(true); } void KisGbrBrush::makeMaskImage() { if (!hasColor()) { return; } QImage brushTip = brushTipImage(); if (brushTip.width() == width() && brushTip.height() == height()) { int imageWidth = width(); int imageHeight = height(); QImage image(imageWidth, imageHeight, QImage::Format_Indexed8); QVector table; for (int i = 0; i < 256; ++i) { table.append(qRgb(i, i, i)); } image.setColorTable(table); for (int y = 0; y < imageHeight; y++) { QRgb *pixel = reinterpret_cast(brushTip.scanLine(y)); uchar * dstPixel = image.scanLine(y); for (int x = 0; x < imageWidth; x++) { QRgb c = pixel[x]; float alpha = qAlpha(c) / 255.0f; // linear interpolation with maximum gray value which is transparent in the mask //int a = (qGray(c) * alpha) + ((1.0 - alpha) * 255); // single multiplication version int a = 255 + alpha * (qGray(c) - 255); dstPixel[x] = (uchar)a; } } setBrushTipImage(image); } setHasColor(false); setUseColorAsMask(false); resetBoundary(); clearBrushPyramid(); } -KisBrush* KisGbrBrush::clone() const +KisBrushSP KisGbrBrush::clone() const { - return new KisGbrBrush(*this); + return KisBrushSP(new KisGbrBrush(*this)); } void KisGbrBrush::toXML(QDomDocument& d, QDomElement& e) const { predefinedBrushToXML("gbr_brush", e); e.setAttribute("ColorAsMask", QString::number((int)useColorAsMask())); KisBrush::toXML(d, e); } void KisGbrBrush::setUseColorAsMask(bool useColorAsMask) { /** * WARNING: There is a problem in the brush server, since it * returns not copies of brushes, but direct pointers to them. It * means that the brushes are shared among all the currently * present paintops, which might be a problem for e.g. Multihand * Brush Tool. * * Right now, all the instances of Multihand Brush Tool share the * same brush, so there is no problem in this sharing, unless we * reset the internal state of the brush on our way. */ if (useColorAsMask != d->useColorAsMask) { d->useColorAsMask = useColorAsMask; resetBoundary(); clearBrushPyramid(); } } bool KisGbrBrush::useColorAsMask() const { return d->useColorAsMask; } QString KisGbrBrush::defaultFileExtension() const { return QString(".gbr"); } diff --git a/libs/brush/kis_gbr_brush.h b/libs/brush/kis_gbr_brush.h index ae14a722f4..d52a71e908 100644 --- a/libs/brush/kis_gbr_brush.h +++ b/libs/brush/kis_gbr_brush.h @@ -1,122 +1,124 @@ /* * Copyright (c) 1999 Matthias Elter * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004 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. */ #ifndef KIS_GBR_BRUSH_ #define KIS_GBR_BRUSH_ #include #include #include "kis_scaling_size_brush.h" #include #include #include #include "kritabrush_export.h" class KisQImagemask; typedef KisSharedPtr KisQImagemaskSP; class QString; class QIODevice; class BRUSH_EXPORT KisGbrBrush : public KisScalingSizeBrush { protected: public: /// Construct brush to load filename later as brush KisGbrBrush(const QString& filename); /// Load brush from the specified data, at position dataPos, and set the filename KisGbrBrush(const QString& filename, const QByteArray & data, qint32 & dataPos); /// Load brush from the specified paint device, in the specified region KisGbrBrush(KisPaintDeviceSP image, int x, int y, int w, int h); /// Load brush as a copy from the specified QImage (handy when you need to copy a brush!) KisGbrBrush(const QImage& image, const QString& name = QString()); KisGbrBrush(const KisGbrBrush& rhs); ~KisGbrBrush() override; bool load() override; bool loadFromDevice(QIODevice *dev) override; bool save() override; bool saveToDevice(QIODevice* dev) const override; /** * @return a preview of the brush */ QImage brushTipImage() const override; /** * If the brush image data are colorful (e.g. you created the brush from the canvas with custom brush) * and you want to paint with it as with masks, set to true. */ virtual void setUseColorAsMask(bool useColorAsMask); virtual bool useColorAsMask() const; /** * Convert the mask to inverted gray scale, so it is alpha mask. * It can be used as MASK brush type. This operates on the date of the brush, * so it destruct the original brush data */ virtual void makeMaskImage(); enumBrushType brushType() const override; /** * Makes a copy of this brush. */ - KisBrush* clone() const override; + KisBrushSP clone() const override; /** * @return default file extension for saving the brush */ QString defaultFileExtension() const override; protected: /** * save the content of this brush to an IO device */ friend class KisImageBrushesPipe; friend class KisBrushExport; void setBrushType(enumBrushType type) override; void setBrushTipImage(const QImage& image) override; void toXML(QDomDocument& d, QDomElement& e) const override; private: bool init(); bool initFromPaintDev(KisPaintDeviceSP image, int x, int y, int w, int h); struct Private; Private* const d; }; +typedef QSharedPointer KisGbrBrushSP; + #endif // KIS_GBR_BRUSH_ diff --git a/libs/brush/kis_imagepipe_brush.cpp b/libs/brush/kis_imagepipe_brush.cpp index 8595772ea1..25219d628a 100644 --- a/libs/brush/kis_imagepipe_brush.cpp +++ b/libs/brush/kis_imagepipe_brush.cpp @@ -1,518 +1,518 @@ /* * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2005 Bart Coppens * * 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_imagepipe_brush.h" #include "kis_pipebrush_parasite.h" #include "kis_brushes_pipe.h" class KisImageBrushesPipe : public KisBrushesPipe { public: KisImageBrushesPipe() : m_isInitialized(false) { } /* pre and post are split because: 21:12:20 < dmitryK> boud: i guess it was somehow related to the fact that the maskWidth/maskHeight should correspond to the size of the mask returned by paintDevice() 21:13:33 < dmitryK> boud: the random stuff is called once per brush->paintDevice() call, after the device is returned to the paint op, that is "preparing the randomness for the next call" 21:14:16 < dmitryK> boud: and brushesPipe->currentBrush() always returning the same brush for any particular paintInfo. */ protected: static int selectPre(KisParasite::SelectionMode mode, int index, int rank, const KisPaintInformation& info) { qreal angle; switch (mode) { case KisParasite::Constant: case KisParasite::Incremental: case KisParasite::Random: break; case KisParasite::Pressure: index = static_cast(info.pressure() * (rank - 1) + 0.5); break; case KisParasite::Angular: // + m_d->PI_2 to be compatible with the gimp angle = info.drawingAngle() + M_PI_2; angle = normalizeAngle(angle); index = static_cast(angle / (2.0 * M_PI) * rank); break; case KisParasite::TiltX: index = qRound(info.xTilt() / 2.0 * rank) + rank / 2; break; case KisParasite::TiltY: index = qRound(info.yTilt() / 2.0 * rank) + rank / 2; break; default: warnImage << "Parasite" << mode << "is not implemented"; index = 0; } return index; } static int selectPost(KisParasite::SelectionMode mode, int index, int rank, const KisPaintInformation& info, int seqNo) { switch (mode) { case KisParasite::Constant: break; case KisParasite::Incremental: index = (seqNo >= 0 ? seqNo : (index + 1)) % rank; break; case KisParasite::Random: index = info.randomSource()->generate(0, rank); break; case KisParasite::Pressure: case KisParasite::Angular: break; case KisParasite::TiltX: case KisParasite::TiltY: break; default: warnImage << "Parasite" << mode << "is not implemented"; index = 0; } return index; } int chooseNextBrush(const KisPaintInformation& info) override { quint32 brushIndex = 0; if (!m_isInitialized) { /** * Reset all the indexes to the initial values and do the * generation based on parameters. */ for (int i = 0; i < m_parasite.dim; i++) { m_parasite.index[i] = 0; } updateBrushIndexes(info, 0); m_isInitialized = true; } for (int i = 0; i < m_parasite.dim; i++) { int index = selectPre(m_parasite.selection[i], m_parasite.index[i], m_parasite.rank[i], info); brushIndex += m_parasite.brushesCount[i] * index; } brushIndex %= m_brushes.size(); return brushIndex; } void updateBrushIndexes(const KisPaintInformation& info, int seqNo) override { for (int i = 0; i < m_parasite.dim; i++) { m_parasite.index[i] = selectPost(m_parasite.selection[i], m_parasite.index[i], m_parasite.rank[i], info, seqNo); } } public: using KisBrushesPipe::addBrush; void setParasite(const KisPipeBrushParasite& parasite) { m_parasite = parasite; } const KisPipeBrushParasite& parasite() const { return m_parasite; } void setUseColorAsMask(bool useColorAsMask) { - Q_FOREACH (KisGbrBrush * brush, m_brushes) { + Q_FOREACH (KisGbrBrushSP brush, m_brushes) { brush->setUseColorAsMask(useColorAsMask); } } void makeMaskImage() { - Q_FOREACH (KisGbrBrush * brush, m_brushes) { + Q_FOREACH (KisGbrBrushSP brush, m_brushes) { brush->makeMaskImage(); } } bool saveToDevice(QIODevice* dev) const { - Q_FOREACH (KisGbrBrush * brush, m_brushes) { + Q_FOREACH (KisGbrBrushSP brush, m_brushes) { if (!brush->saveToDevice(dev)) { return false; } } return true; } void notifyStrokeStarted() override { m_isInitialized = false; } private: KisPipeBrushParasite m_parasite; bool m_isInitialized; }; struct KisImagePipeBrush::Private { public: KisImageBrushesPipe brushesPipe; }; KisImagePipeBrush::KisImagePipeBrush(const QString& filename) : KisGbrBrush(filename) , m_d(new Private()) { } KisImagePipeBrush::KisImagePipeBrush(const QString& name, int w, int h, QVector< QVector > devices, QVector modes) : KisGbrBrush(QString()) , m_d(new Private()) { Q_ASSERT(devices.count() == modes.count()); Q_ASSERT(devices.count() > 0); Q_ASSERT(devices.count() < 2); // XXX Multidimensionals not supported yet, change to MaxDim! setName(name); KisPipeBrushParasite parasite; parasite.dim = devices.count(); // XXX Change for multidim! : parasite.ncells = devices.at(0).count(); parasite.rank[0] = parasite.ncells; // ### This can masquerade some bugs, be careful here in the future parasite.selection[0] = modes.at(0); // XXX needsmovement! parasite.setBrushesCount(); setParasite(parasite); setDevices(devices, w, h); setBrushTipImage(m_d->brushesPipe.firstBrush()->brushTipImage()); } KisImagePipeBrush::KisImagePipeBrush(const KisImagePipeBrush& rhs) : KisGbrBrush(rhs), m_d(new Private(*rhs.m_d)) { } KisImagePipeBrush::~KisImagePipeBrush() { delete m_d; } bool KisImagePipeBrush::load() { QFile file(filename()); file.open(QIODevice::ReadOnly); bool res = loadFromDevice(&file); file.close(); return res; } bool KisImagePipeBrush::loadFromDevice(QIODevice *dev) { QByteArray data = dev->readAll(); return initFromData(data); } bool KisImagePipeBrush::initFromData(const QByteArray &data) { if (data.size() == 0) return false; // XXX: this doesn't correctly load the image pipe brushes yet. // XXX: This stuff is in utf-8, too. // The first line contains the name -- this means we look until we arrive at the first newline QByteArray line1; qint32 i = 0; while (data[i] != '\n' && i < data.size()) { line1.append(data[i]); i++; } setName(QString::fromUtf8(line1, line1.size())); i++; // Skip past the first newline // The second line contains the number of brushes, separated by a space from the parasite // XXX: This stuff is in utf-8, too. QByteArray line2; while (data[i] != '\n' && i < data.size()) { line2.append(data[i]); i++; } QString paramline = QString::fromUtf8(line2, line2.size()); qint32 numOfBrushes = paramline.left(paramline.indexOf(' ')).toUInt(); QString parasiteString = paramline.mid(paramline.indexOf(' ') + 1); KisPipeBrushParasite parasite = KisPipeBrushParasite(parasiteString); parasite.sanitize(); parasiteSelectionString = parasite.selectionMode; // selection mode to return to UI m_d->brushesPipe.setParasite(parasite); i++; // Skip past the second newline for (int brushIndex = 0; brushIndex < numOfBrushes && i < data.size(); brushIndex++) { - KisGbrBrush* brush = new KisGbrBrush(name() + '_' + QString().setNum(brushIndex), + KisGbrBrushSP brush = KisGbrBrushSP(new KisGbrBrush(name() + '_' + QString().setNum(brushIndex), data, - i); + i)); m_d->brushesPipe.addBrush(brush); } if (numOfBrushes > 0) { setValid(true); setSpacing(m_d->brushesPipe.lastBrush()->spacing()); setWidth(m_d->brushesPipe.firstBrush()->width()); setHeight(m_d->brushesPipe.firstBrush()->height()); setBrushTipImage(m_d->brushesPipe.firstBrush()->brushTipImage()); } return true; } bool KisImagePipeBrush::save() { QFile file(filename()); file.open(QIODevice::WriteOnly | QIODevice::Truncate); bool ok = saveToDevice(&file); file.close(); return ok; } bool KisImagePipeBrush::saveToDevice(QIODevice* dev) const { QByteArray utf8Name = name().toUtf8(); // Names in v2 brushes are in UTF-8 char const* name = utf8Name.data(); int len = qstrlen(name); if (m_d->brushesPipe.parasite().dim != 1) { warnImage << "Save to file for pipe brushes with dim != not yet supported!"; return false; } // Save this pipe brush: first the header, and then all individual brushes consecutively // XXX: this needs some care for when we have > 1 dimension) // Gimp Pipe Brush header format: Name\n \n // The name\n if (dev->write(name, len) == -1) return false; if (!dev->putChar('\n')) return false; // Write the parasite (also writes number of brushes) if (!m_d->brushesPipe.parasite().saveToDevice(dev)) return false; if (!dev->putChar('\n')) return false; KoResource::saveToDevice(dev); // return m_d->brushesPipe.saveToDevice(dev); } void KisImagePipeBrush::notifyStrokeStarted() { m_d->brushesPipe.notifyStrokeStarted(); } void KisImagePipeBrush::notifyCachedDabPainted(const KisPaintInformation& info) { m_d->brushesPipe.notifyCachedDabPainted(info); } void KisImagePipeBrush::prepareForSeqNo(const KisPaintInformation &info, int seqNo) { m_d->brushesPipe.prepareForSeqNo(info, seqNo); } void KisImagePipeBrush::generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst, KisBrush::ColoringInformation* coloringInformation, KisDabShape const& shape, const KisPaintInformation& info, double subPixelX , double subPixelY, qreal softnessFactor) const { m_d->brushesPipe.generateMaskAndApplyMaskOrCreateDab(dst, coloringInformation, shape, info, subPixelX, subPixelY, softnessFactor); } -QVector KisImagePipeBrush::brushes() const +QVector KisImagePipeBrush::brushes() const { return m_d->brushesPipe.brushes(); } KisFixedPaintDeviceSP KisImagePipeBrush::paintDevice( const KoColorSpace * colorSpace, KisDabShape const& shape, const KisPaintInformation& info, double subPixelX, double subPixelY) const { return m_d->brushesPipe.paintDevice(colorSpace, shape, info, subPixelX, subPixelY); } enumBrushType KisImagePipeBrush::brushType() const { return !hasColor() || useColorAsMask() ? PIPE_MASK : PIPE_IMAGE; } QString KisImagePipeBrush::parasiteSelection() { return parasiteSelectionString; } bool KisImagePipeBrush::hasColor() const { return m_d->brushesPipe.hasColor(); } void KisImagePipeBrush::makeMaskImage() { m_d->brushesPipe.makeMaskImage(); setUseColorAsMask(false); } void KisImagePipeBrush::setUseColorAsMask(bool useColorAsMask) { KisGbrBrush::setUseColorAsMask(useColorAsMask); m_d->brushesPipe.setUseColorAsMask(useColorAsMask); } const KisBoundary* KisImagePipeBrush::boundary() const { - KisGbrBrush *brush = m_d->brushesPipe.firstBrush(); + KisGbrBrushSP brush = m_d->brushesPipe.firstBrush(); Q_ASSERT(brush); return brush->boundary(); } bool KisImagePipeBrush::canPaintFor(const KisPaintInformation& info) { return (!m_d->brushesPipe.parasite().needsMovement || info.drawingDistance() >= 0.5); } -KisBrush* KisImagePipeBrush::clone() const +KisBrushSP KisImagePipeBrush::clone() const { - return new KisImagePipeBrush(*this); + return KisBrushSP(new KisImagePipeBrush(*this)); } QString KisImagePipeBrush::defaultFileExtension() const { return QString(".gih"); } quint32 KisImagePipeBrush::brushIndex(const KisPaintInformation& info) const { return m_d->brushesPipe.brushIndex(info); } qint32 KisImagePipeBrush::maskWidth(KisDabShape const& shape, double subPixelX, double subPixelY, const KisPaintInformation& info) const { return m_d->brushesPipe.maskWidth(shape, subPixelX, subPixelY, info); } qint32 KisImagePipeBrush::maskHeight(KisDabShape const& shape, double subPixelX, double subPixelY, const KisPaintInformation& info) const { return m_d->brushesPipe.maskHeight(shape, subPixelX, subPixelY, info); } void KisImagePipeBrush::setAngle(qreal _angle) { KisGbrBrush::setAngle(_angle); m_d->brushesPipe.setAngle(_angle); } void KisImagePipeBrush::setScale(qreal _scale) { KisGbrBrush::setScale(_scale); m_d->brushesPipe.setScale(_scale); } void KisImagePipeBrush::setSpacing(double _spacing) { KisGbrBrush::setSpacing(_spacing); m_d->brushesPipe.setSpacing(_spacing); } void KisImagePipeBrush::setBrushType(enumBrushType type) { Q_UNUSED(type); qFatal("FATAL: protected member setBrushType has no meaning for KisImagePipeBrush"); // brushType() is a function of hasColor() and useColorAsMask() } void KisImagePipeBrush::setHasColor(bool hasColor) { Q_UNUSED(hasColor); qFatal("FATAL: protected member setHasColor has no meaning for KisImagePipeBrush"); // hasColor() is a function of the underlying brushes } -KisGbrBrush* KisImagePipeBrush::testingGetCurrentBrush(const KisPaintInformation& info) const +KisGbrBrushSP KisImagePipeBrush::testingGetCurrentBrush(const KisPaintInformation& info) const { return m_d->brushesPipe.currentBrush(info); } void KisImagePipeBrush::testingSelectNextBrush(const KisPaintInformation& info) const { return m_d->brushesPipe.testingSelectNextBrush(info); } const KisPipeBrushParasite& KisImagePipeBrush::parasite() const { return m_d->brushesPipe.parasite(); } void KisImagePipeBrush::setParasite(const KisPipeBrushParasite ¶site) { m_d->brushesPipe.setParasite(parasite); } void KisImagePipeBrush::setDevices(QVector > devices, int w, int h) { for (int i = 0; i < devices.at(0).count(); i++) { - m_d->brushesPipe.addBrush(new KisGbrBrush(devices.at(0).at(i), 0, 0, w, h)); + m_d->brushesPipe.addBrush(KisGbrBrushSP(new KisGbrBrush(devices.at(0).at(i), 0, 0, w, h))); } } diff --git a/libs/brush/kis_imagepipe_brush.h b/libs/brush/kis_imagepipe_brush.h index f36a285f83..0ee9760aec 100644 --- a/libs/brush/kis_imagepipe_brush.h +++ b/libs/brush/kis_imagepipe_brush.h @@ -1,144 +1,143 @@ /* * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2005 Bart Coppens * * 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_IMAGEPIPE_BRUSH_ #define KIS_IMAGEPIPE_BRUSH_ #include #include #include #include #include "kis_gbr_brush.h" #include "kis_global.h" class KisPipeBrushParasite; /** * Velocity won't be supported, atm Tilt isn't either, * but have chances of implementation */ namespace KisParasite { enum SelectionMode { Constant, Incremental, Angular, Velocity, Random, Pressure, TiltX, TiltY }; } class BRUSH_EXPORT KisImagePipeBrush : public KisGbrBrush { public: KisImagePipeBrush(const QString& filename); /** * Specialized constructor that makes a new pipe brush from a sequence of samesize * devices. The fact that it's a vector of a vector, is to support multidimensional * brushes (not yet supported!) */ KisImagePipeBrush(const QString& name, int w, int h, QVector< QVector > devices, QVector modes); ~KisImagePipeBrush() override; bool load() override; bool loadFromDevice(QIODevice *dev) override; bool save() override; bool saveToDevice(QIODevice* dev) const override; /** * @return the next image in the pipe. */ KisFixedPaintDeviceSP paintDevice(const KoColorSpace * colorSpace, KisDabShape const&, const KisPaintInformation& info, double subPixelX = 0, double subPixelY = 0) const override; void setUseColorAsMask(bool useColorAsMask) override; bool hasColor() const override; enumBrushType brushType() const override; QString parasiteSelection(); // returns random, constant, etc const KisBoundary* boundary() const override; bool canPaintFor(const KisPaintInformation& info) override; void makeMaskImage() override; - KisBrush* clone() const override; + KisBrushSP clone() const override; QString defaultFileExtension() const override; void setAngle(qreal _angle) override; void setScale(qreal _scale) override; void setSpacing(double _spacing) override; quint32 brushIndex(const KisPaintInformation& info) const override; qint32 maskWidth(KisDabShape const&, double subPixelX, double subPixelY, const KisPaintInformation& info) const override; qint32 maskHeight(KisDabShape const&, double subPixelX, double subPixelY, const KisPaintInformation& info) const override; void notifyStrokeStarted() override; void notifyCachedDabPainted(const KisPaintInformation& info) override; void prepareForSeqNo(const KisPaintInformation& info, int seqNo) override; void generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst, KisBrush::ColoringInformation* coloringInformation, KisDabShape const&, const KisPaintInformation& info, double subPixelX = 0, double subPixelY = 0, qreal softnessFactor = DEFAULT_SOFTNESS_FACTOR) const override; - QVector brushes() const; + QVector brushes() const; const KisPipeBrushParasite ¶site() const; void setParasite(const KisPipeBrushParasite& parasite); void setDevices(QVector< QVector > devices, int w, int h); protected: void setBrushType(enumBrushType type) override; void setHasColor(bool hasColor) override; /// Will call KisBrush's saveToDevice as well KisImagePipeBrush(const KisImagePipeBrush& rhs); private: friend class KisImagePipeBrushTest; - KisGbrBrush* testingGetCurrentBrush(const KisPaintInformation& info) const; + KisGbrBrushSP testingGetCurrentBrush(const KisPaintInformation& info) const; void testingSelectNextBrush(const KisPaintInformation& info) const; bool initFromData(const QByteArray &data); QString parasiteSelectionString; // incremental, random, etc. private: struct Private; Private * const m_d; - - - }; +typedef QSharedPointer KisImagePipeBrushSP; + #endif // KIS_IMAGEPIPE_BRUSH_ diff --git a/libs/brush/kis_png_brush.cpp b/libs/brush/kis_png_brush.cpp index eb5e8e909c..a4d8f1f773 100644 --- a/libs/brush/kis_png_brush.cpp +++ b/libs/brush/kis_png_brush.cpp @@ -1,152 +1,152 @@ /* * Copyright (c) 2010 Cyrille Berger * * 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_png_brush.h" #include #include #include #include #include #include KisPngBrush::KisPngBrush(const QString& filename) : KisScalingSizeBrush(filename) { setBrushType(INVALID); setSpacing(0.25); setHasColor(false); } KisPngBrush::KisPngBrush(const KisPngBrush &rhs) : KisScalingSizeBrush(rhs) { setSpacing(rhs.spacing()); if (brushTipImage().isGrayscale()) { setBrushType(MASK); setHasColor(false); } else { setBrushType(IMAGE); setHasColor(true); } } -KisBrush* KisPngBrush::clone() const +KisBrushSP KisPngBrush::clone() const { - return new KisPngBrush(*this); + return KisBrushSP(new KisPngBrush(*this)); } bool KisPngBrush::load() { QFile f(filename()); if (f.size() == 0) return false; if (!f.exists()) return false; if (!f.open(QIODevice::ReadOnly)) { warnKrita << "Can't open file " << filename(); return false; } bool res = loadFromDevice(&f); f.close(); return res; } bool KisPngBrush::loadFromDevice(QIODevice *dev) { // Workaround for some OS (Debian, Ubuntu), where loading directly from the QIODevice // fails with "libpng error: IDAT: CRC error" QByteArray data = dev->readAll(); QBuffer buf(&data); buf.open(QIODevice::ReadOnly); QImageReader reader(&buf, "PNG"); if (!reader.canRead()) { dbgKrita << "Could not read brush" << filename() << ". Error:" << reader.errorString(); setValid(false); return false; } if (reader.textKeys().contains("brush_spacing")) { setSpacing(KisDomUtils::toDouble(reader.text("brush_spacing"))); } if (reader.textKeys().contains("brush_name")) { setName(reader.text("brush_name")); } else { QFileInfo info(filename()); setName(info.baseName()); } QImage image = reader.read(); if (image.isNull()) { dbgKrita << "Could not create image for" << filename() << ". Error:" << reader.errorString(); setValid(false); return false; } setBrushTipImage(image); setValid(true); if (brushTipImage().isGrayscale()) { setBrushType(MASK); setHasColor(false); } else { setBrushType(IMAGE); setHasColor(true); } setWidth(brushTipImage().width()); setHeight(brushTipImage().height()); return valid(); } bool KisPngBrush::save() { QFile f(filename()); if (!f.open(QFile::WriteOnly)) return false; bool res = saveToDevice(&f); f.close(); return res; } bool KisPngBrush::saveToDevice(QIODevice *dev) const { if(brushTipImage().save(dev, "PNG")) { KoResource::saveToDevice(dev); return true; } return false; } QString KisPngBrush::defaultFileExtension() const { return QString(".png"); } void KisPngBrush::toXML(QDomDocument& d, QDomElement& e) const { predefinedBrushToXML("png_brush", e); KisBrush::toXML(d, e); } diff --git a/libs/brush/kis_png_brush.h b/libs/brush/kis_png_brush.h index d8ceb9cc20..1dae218953 100644 --- a/libs/brush/kis_png_brush.h +++ b/libs/brush/kis_png_brush.h @@ -1,41 +1,41 @@ /* * Copyright (c) 2010 Cyrille Berger * * 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_PNG_BRUSH_ #define KIS_PNG_BRUSH_ #include "kis_scaling_size_brush.h" class BRUSH_EXPORT KisPngBrush : public KisScalingSizeBrush { public: /// Construct brush to load filename later as brush KisPngBrush(const QString& filename); KisPngBrush(const KisPngBrush &rhs); - KisBrush* clone() const override; + KisBrushSP clone() const override; bool load() override; bool loadFromDevice(QIODevice *dev) override; bool save() override; bool saveToDevice(QIODevice *dev) const override; QString defaultFileExtension() const override; void toXML(QDomDocument& d, QDomElement& e) const override; }; #endif diff --git a/libs/brush/kis_svg_brush.cpp b/libs/brush/kis_svg_brush.cpp index c8469dfad4..54b10e0d58 100644 --- a/libs/brush/kis_svg_brush.cpp +++ b/libs/brush/kis_svg_brush.cpp @@ -1,132 +1,132 @@ /* * Copyright (c) 2010 Cyrille Berger * * 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_svg_brush.h" #include #include #include #include #include KisSvgBrush::KisSvgBrush(const QString& filename) : KisScalingSizeBrush(filename) { setBrushType(INVALID); setSpacing(0.25); setHasColor(false); } KisSvgBrush::KisSvgBrush(const KisSvgBrush& rhs) : KisScalingSizeBrush(rhs) , m_svg(rhs.m_svg) { } -KisBrush* KisSvgBrush::clone() const +KisBrushSP KisSvgBrush::clone() const { - return new KisSvgBrush(*this); + return KisBrushSP(new KisSvgBrush(*this)); } bool KisSvgBrush::load() { QFile f(filename()); if (f.size() == 0) return false; if (!f.exists()) return false; if (!f.open(QIODevice::ReadOnly)) { warnKrita << "Can't open file " << filename(); return false; } bool res = loadFromDevice(&f); f.close(); return res; } bool KisSvgBrush::loadFromDevice(QIODevice *dev) { m_svg = dev->readAll(); QSvgRenderer renderer(m_svg); QRect box = renderer.viewBox(); if (box.isEmpty()) return false; QImage image_(1000, (1000 * box.height()) / box.width(), QImage::Format_ARGB32); { QPainter p(&image_); p.fillRect(0, 0, image_.width(), image_.height(), Qt::white); renderer.render(&p); } QVector table; for (int i = 0; i < 256; ++i) table.push_back(qRgb(i, i, i)); image_ = image_.convertToFormat(QImage::Format_Indexed8, table); setBrushTipImage(image_); setValid(true); // Well for now, always true if (brushTipImage().isGrayscale()) { setBrushType(MASK); setHasColor(false); } else { setBrushType(IMAGE); setHasColor(true); } setWidth(brushTipImage().width()); setHeight(brushTipImage().height()); QFileInfo fi(filename()); setName(fi.baseName()); return !brushTipImage().isNull() && valid(); } bool KisSvgBrush::save() { QFile f(filename()); if (!f.open(QFile::WriteOnly)) return false; bool res = saveToDevice(&f); f.close(); return res; } bool KisSvgBrush::saveToDevice(QIODevice *dev) const { if((dev->write(m_svg.constData(), m_svg.size()) == m_svg.size())) { KoResource::saveToDevice(dev); return true; } return false; } QString KisSvgBrush::defaultFileExtension() const { return QString(".svg"); } void KisSvgBrush::toXML(QDomDocument& d, QDomElement& e) const { predefinedBrushToXML("svg_brush", e); KisBrush::toXML(d, e); } diff --git a/libs/brush/kis_svg_brush.h b/libs/brush/kis_svg_brush.h index 16f0d47d14..82aec4eb6b 100644 --- a/libs/brush/kis_svg_brush.h +++ b/libs/brush/kis_svg_brush.h @@ -1,43 +1,43 @@ /* * Copyright (c) 2010 Cyrille Berger * * 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_SVG_BRUSH_ #define KIS_SVG_BRUSH_ #include "kis_scaling_size_brush.h" class BRUSH_EXPORT KisSvgBrush : public KisScalingSizeBrush { public: /// Construct brush to load filename later as brush KisSvgBrush(const QString& filename); KisSvgBrush(const KisSvgBrush& rhs); - KisBrush* clone() const override; + KisBrushSP clone() const override; bool load() override; bool loadFromDevice(QIODevice *dev) override; bool save() override; bool saveToDevice(QIODevice *dev) const override; QString defaultFileExtension() const override; void toXML(QDomDocument& d, QDomElement& e) const override; private: QByteArray m_svg; }; #endif diff --git a/libs/brush/kis_text_brush.cpp b/libs/brush/kis_text_brush.cpp index 6a73c97f01..4a18698f18 100644 --- a/libs/brush/kis_text_brush.cpp +++ b/libs/brush/kis_text_brush.cpp @@ -1,334 +1,334 @@ /* * Copyright (c) 2004 Cyrille Berger * Copyright (c) 2011 Lukáš Tvrdý * * 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_text_brush.h" #include #include #include #include #include "kis_gbr_brush.h" #include "kis_brushes_pipe.h" #include #include #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND #include #include #include #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ class KisTextBrushesPipe : public KisBrushesPipe { public: KisTextBrushesPipe() { m_charIndex = 0; m_currentBrushIndex = 0; } KisTextBrushesPipe(const KisTextBrushesPipe &rhs) : KisBrushesPipe(), // no copy here! m_text(rhs.m_text), m_charIndex(rhs.m_charIndex), m_currentBrushIndex(rhs.m_currentBrushIndex) { m_brushesMap.clear(); - QMapIterator iter(rhs.m_brushesMap); + QMapIterator iter(rhs.m_brushesMap); while (iter.hasNext()) { iter.next(); - KisGbrBrush *brush = new KisGbrBrush(*iter.value()); + KisGbrBrushSP brush(new KisGbrBrush(*iter.value())); m_brushesMap.insert(iter.key(), brush); KisBrushesPipe::addBrush(brush); } } void setText(const QString &text, const QFont &font) { m_text = text; m_charIndex = 0; clear(); for (int i = 0; i < m_text.length(); i++) { const QChar letter = m_text.at(i); // skip letters that are already present in the brushes pipe if (m_brushesMap.contains(letter)) continue; QImage image = renderChar(letter, font); - KisGbrBrush *brush = new KisGbrBrush(image, letter); + KisGbrBrushSP brush(new KisGbrBrush(image, letter)); brush->setSpacing(0.1); // support for letter spacing? brush->makeMaskImage(); m_brushesMap.insert(letter, brush); KisBrushesPipe::addBrush(brush); } } static QImage renderChar(const QString& text, const QFont &font) { #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND QWidget *focusWidget = qApp->focusWidget(); if (focusWidget) { QThread *guiThread = focusWidget->thread(); if (guiThread != QThread::currentThread()) { warnKrita << "WARNING: Rendering text in non-GUI thread!" << "That may lead to hangups and crashes on some" << "versions of X11/Qt!"; } } #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ QFontMetrics metric(font); QRect rect = metric.boundingRect(text); if (rect.isEmpty()) { rect = QRect(0, 0, 1, 1); // paint at least something } QRect paintingRect = rect.translated(-rect.x(), -rect.y()); QImage renderedChar(paintingRect.size(), QImage::Format_ARGB32); QPainter p; p.begin(&renderedChar); p.setFont(font); p.fillRect(paintingRect, Qt::white); p.setPen(Qt::black); p.drawText(-rect.x(), -rect.y(), text); p.end(); return renderedChar; } void clear() override { m_brushesMap.clear(); KisBrushesPipe::clear(); } - KisGbrBrush* firstBrush() const { + KisGbrBrushSP firstBrush() const { Q_ASSERT(m_text.size() > 0); Q_ASSERT(m_brushesMap.size() > 0); return m_brushesMap.value(m_text.at(0)); } void notifyStrokeStarted() override { m_charIndex = 0; updateBrushIndexesImpl(); } protected: int chooseNextBrush(const KisPaintInformation& info) override { Q_UNUSED(info); return m_currentBrushIndex; } void updateBrushIndexes(const KisPaintInformation& info, int seqNo) override { Q_UNUSED(info); if (m_text.size()) { m_charIndex = (seqNo >= 0 ? seqNo : (m_charIndex + 1)) % m_text.size(); } else { m_charIndex = 0; } updateBrushIndexesImpl(); } private: void updateBrushIndexesImpl() { if (m_text.isEmpty()) return; if (m_charIndex >= m_text.size()) { m_charIndex = 0; } QChar letter = m_text.at(m_charIndex); Q_ASSERT(m_brushesMap.contains(letter)); m_currentBrushIndex = m_brushes.indexOf(m_brushesMap.value(letter)); } private: - QMap m_brushesMap; + QMap m_brushesMap; QString m_text; int m_charIndex; int m_currentBrushIndex; }; KisTextBrush::KisTextBrush() : m_brushesPipe(new KisTextBrushesPipe()) { setPipeMode(false); } KisTextBrush::KisTextBrush(const KisTextBrush &rhs) : KisScalingSizeBrush(rhs), m_font(rhs.m_font), m_text(rhs.m_text), m_brushesPipe(new KisTextBrushesPipe(*rhs.m_brushesPipe)) { } KisTextBrush::~KisTextBrush() { delete m_brushesPipe; } void KisTextBrush::setPipeMode(bool pipe) { setBrushType(pipe ? PIPE_MASK : MASK); } bool KisTextBrush::pipeMode() const { return brushType() == PIPE_MASK; } void KisTextBrush::setText(const QString& txt) { m_text = txt; } QString KisTextBrush::text(void) const { return m_text; } void KisTextBrush::setFont(const QFont& font) { m_font = font; } QFont KisTextBrush::font() { return m_font; } void KisTextBrush::notifyStrokeStarted() { m_brushesPipe->notifyStrokeStarted(); } void KisTextBrush::notifyCachedDabPainted(const KisPaintInformation& info) { m_brushesPipe->notifyCachedDabPainted(info); } void KisTextBrush::prepareForSeqNo(const KisPaintInformation &info, int seqNo) { m_brushesPipe->prepareForSeqNo(info, seqNo); } void KisTextBrush::generateMaskAndApplyMaskOrCreateDab( KisFixedPaintDeviceSP dst, KisBrush::ColoringInformation* coloringInformation, KisDabShape const& shape, const KisPaintInformation& info, double subPixelX, double subPixelY, qreal softnessFactor) const { if (brushType() == MASK) { KisBrush::generateMaskAndApplyMaskOrCreateDab(dst, coloringInformation, shape, info, subPixelX, subPixelY, softnessFactor); } else { /* if (brushType() == PIPE_MASK)*/ m_brushesPipe->generateMaskAndApplyMaskOrCreateDab(dst, coloringInformation, shape, info, subPixelX, subPixelY, softnessFactor); } } KisFixedPaintDeviceSP KisTextBrush::paintDevice(const KoColorSpace * colorSpace, KisDabShape const& shape, const KisPaintInformation& info, double subPixelX, double subPixelY) const { if (brushType() == MASK) { return KisBrush::paintDevice(colorSpace, shape, info, subPixelX, subPixelY); } else { /* if (brushType() == PIPE_MASK)*/ return m_brushesPipe->paintDevice(colorSpace, shape, info, subPixelX, subPixelY); } } void KisTextBrush::toXML(QDomDocument& doc, QDomElement& e) const { Q_UNUSED(doc); e.setAttribute("type", "kis_text_brush"); e.setAttribute("spacing", KisDomUtils::toString(spacing())); e.setAttribute("text", m_text); e.setAttribute("font", m_font.toString()); e.setAttribute("pipe", (brushType() == PIPE_MASK) ? "true" : "false"); KisBrush::toXML(doc, e); } void KisTextBrush::updateBrush() { Q_ASSERT((brushType() == PIPE_MASK) || (brushType() == MASK)); if (brushType() == PIPE_MASK) { m_brushesPipe->setText(m_text, m_font); setBrushTipImage(m_brushesPipe->firstBrush()->brushTipImage()); } else { /* if (brushType() == MASK)*/ setBrushTipImage(KisTextBrushesPipe::renderChar(m_text, m_font)); } resetBoundary(); setValid(true); } quint32 KisTextBrush::brushIndex(const KisPaintInformation& info) const { return brushType() == MASK ? 0 : 1 + m_brushesPipe->brushIndex(info); } qint32 KisTextBrush::maskWidth(KisDabShape const& shape, double subPixelX, double subPixelY, const KisPaintInformation& info) const { return brushType() == MASK ? KisBrush::maskWidth(shape, subPixelX, subPixelY, info) : m_brushesPipe->maskWidth(shape, subPixelX, subPixelY, info); } qint32 KisTextBrush::maskHeight(KisDabShape const& shape, double subPixelX, double subPixelY, const KisPaintInformation& info) const { return brushType() == MASK ? KisBrush::maskHeight(shape, subPixelX, subPixelY, info) : m_brushesPipe->maskHeight(shape, subPixelX, subPixelY, info); } void KisTextBrush::setAngle(qreal _angle) { KisBrush::setAngle(_angle); m_brushesPipe->setAngle(_angle); } void KisTextBrush::setScale(qreal _scale) { KisBrush::setScale(_scale); m_brushesPipe->setScale(_scale); } void KisTextBrush::setSpacing(double _spacing) { KisBrush::setSpacing(_spacing); m_brushesPipe->setSpacing(_spacing); } -KisBrush* KisTextBrush::clone() const +KisBrushSP KisTextBrush::clone() const { - return new KisTextBrush(*this); + return KisBrushSP(new KisTextBrush(*this)); } diff --git a/libs/brush/kis_text_brush.h b/libs/brush/kis_text_brush.h index 01dfed2854..468852bc02 100644 --- a/libs/brush/kis_text_brush.h +++ b/libs/brush/kis_text_brush.h @@ -1,96 +1,98 @@ /* * Copyright (c) 2004 Cyrille Berger * Copyright (c) 2011 Lukáš Tvrdý * * 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_TEXT_BRUSH_H_ #define _KIS_TEXT_BRUSH_H_ #include #include "kis_scaling_size_brush.h" #include "kritabrush_export.h" class KisTextBrushesPipe; class BRUSH_EXPORT KisTextBrush : public KisScalingSizeBrush { public: KisTextBrush(); KisTextBrush(const KisTextBrush &rhs); ~KisTextBrush() override; void notifyStrokeStarted() override; void notifyCachedDabPainted(const KisPaintInformation& info) override; void prepareForSeqNo(const KisPaintInformation& info, int seqNo) override; void generateMaskAndApplyMaskOrCreateDab(KisFixedPaintDeviceSP dst, KisBrush::ColoringInformation* coloringInformation, KisDabShape const&, const KisPaintInformation& info, double subPixelX = 0, double subPixelY = 0, qreal softnessFactor = DEFAULT_SOFTNESS_FACTOR) const override; KisFixedPaintDeviceSP paintDevice(const KoColorSpace * colorSpace, KisDabShape const&, const KisPaintInformation& info, double subPixelX, double subPixelY) const override; bool load() override { return false; } bool loadFromDevice(QIODevice *) override { return false; } bool save() override { return false; } bool saveToDevice(QIODevice* ) const override { return false; } void setText(const QString& txt); QString text(void) const; QFont font(); void setFont(const QFont& font); void setPipeMode(bool pipe); bool pipeMode() const; void updateBrush(); void toXML(QDomDocument& , QDomElement&) const override; quint32 brushIndex(const KisPaintInformation& info) const override; qint32 maskWidth(KisDabShape const&, double subPixelX, double subPixelY, const KisPaintInformation& info) const override; qint32 maskHeight(KisDabShape const&, double subPixelX, double subPixelY, const KisPaintInformation& info) const override; void setAngle(qreal _angle) override; void setScale(qreal _scale) override; void setSpacing(double _spacing) override; - KisBrush* clone() const override; + KisBrushSP clone() const override; private: QFont m_font; QString m_text; private: KisTextBrushesPipe *m_brushesPipe; }; +typedef QSharedPointer KisTextBrushSP; + #endif diff --git a/libs/brush/kis_text_brush_factory.cpp b/libs/brush/kis_text_brush_factory.cpp index 1d7fad257f..f1d8984253 100644 --- a/libs/brush/kis_text_brush_factory.cpp +++ b/libs/brush/kis_text_brush_factory.cpp @@ -1,46 +1,43 @@ /* * Copyright (c) 2008 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_text_brush_factory.h" #include #include #include #include "kis_text_brush.h" KisBrushSP KisTextBrushFactory::createBrush(const QDomElement& brushDefinition) { QString text = brushDefinition.attribute("text", "The quick brown fox ate your text"); QFont font; font.fromString(brushDefinition.attribute("font")); double spacing = KisDomUtils::toDouble(brushDefinition.attribute("spacing", "1.0")); QString pipeMode = brushDefinition.attribute("pipe", "false"); bool pipe = (pipeMode == "true") ? true : false; - KisBrushSP b = new KisTextBrush(); - - KisTextBrush *brush = dynamic_cast(b.data()); + KisTextBrushSP brush = KisTextBrushSP(new KisTextBrush()); brush->setText(text); brush->setFont(font); brush->setPipeMode(pipe); brush->setSpacing(spacing); brush->updateBrush(); - return b; - + return brush; } diff --git a/libs/brush/tests/kis_auto_brush_factory_test.cpp b/libs/brush/tests/kis_auto_brush_factory_test.cpp index 724d027f3f..7ae212c637 100644 --- a/libs/brush/tests/kis_auto_brush_factory_test.cpp +++ b/libs/brush/tests/kis_auto_brush_factory_test.cpp @@ -1,51 +1,50 @@ #include "kis_auto_brush_factory_test.h" #include #include #include "kis_auto_brush.h" #include "kis_auto_brush_factory.h" #include "kis_mask_generator.h" #include #include void KisAutoBrushFactoryTest::testXMLClone() { // Set up an autobrush. - KisBrushSP brush = new KisAutoBrush(new KisCircleMaskGenerator(20, 0.6, 0.8, 0.4, 3, true), 1.0, - 0.0); + KisBrushSP brush(new KisAutoBrush(new KisCircleMaskGenerator(20, 0.6, 0.8, 0.4, 3, true), 1.0, 0.0)); brush->setSpacing(0.15); brush->setAutoSpacing(true, 0.1); // Try to clone the brush by converting to XML and back. QDomDocument d; QDomElement e = d.createElement("Brush"); brush->toXML(d, e); KisBrushSP clone = KisAutoBrushFactory().createBrush(e); // Test that the clone has the same settings as the original brush. QCOMPARE(brush->width(), clone->width()); QCOMPARE(brush->height(), clone->height()); QCOMPARE(brush->angle(), clone->angle()); QCOMPARE(brush->spacing(), clone->spacing()); QCOMPARE(brush->autoSpacingActive(), clone->autoSpacingActive()); QCOMPARE(brush->autoSpacingCoeff(), clone->autoSpacingCoeff()); // Test that the clone draws the same as the original brush. const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8(); KisPaintInformation info(QPointF(100.0, 100.0), 0.5); KisDabShape shape(0.9, 0.7, 1.0); KoColor color(Qt::yellow, cs); KisFixedPaintDeviceSP fdev1 = new KisFixedPaintDevice(cs); brush->mask(fdev1, color, shape, info); QImage res1 = fdev1->convertToQImage(0); KisFixedPaintDeviceSP fdev2 = new KisFixedPaintDevice(cs); clone->mask(fdev2, color, shape, info); QImage res2 = fdev2->convertToQImage(0); QCOMPARE(res1, res2); } QTEST_MAIN(KisAutoBrushFactoryTest) diff --git a/libs/brush/tests/kis_auto_brush_test.cpp b/libs/brush/tests/kis_auto_brush_test.cpp index 3d8144c675..f541b51d4c 100644 --- a/libs/brush/tests/kis_auto_brush_test.cpp +++ b/libs/brush/tests/kis_auto_brush_test.cpp @@ -1,196 +1,196 @@ /* * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org * Copyright (c) 2009 Cyrille Berger * * 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 //MSVC requires that Vc come first #include "kis_auto_brush_test.h" #include #include #include "../kis_auto_brush.h" #include "kis_mask_generator.h" #include "kis_paint_device.h" #include "kis_fill_painter.h" #include #include #include #include #include #include void KisAutoBrushTest::testCreation() { KisCircleMaskGenerator circle(10, 1.0, 1.0, 1.0, 2, true); KisRectangleMaskGenerator rect(10, 1.0, 1.0, 1.0, 2, true); } void KisAutoBrushTest::testMaskGeneration() { KisCircleMaskGenerator* circle = new KisCircleMaskGenerator(10, 1.0, 1.0, 1.0, 2, false); - KisBrushSP a = new KisAutoBrush(circle, 0.0, 0.0); + KisBrushSP a(new KisAutoBrush(circle, 0.0, 0.0)); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisPaintInformation info(QPointF(100.0, 100.0), 0.5); // check masking an existing paint device KisFixedPaintDeviceSP fdev = new KisFixedPaintDevice(cs); fdev->setRect(QRect(0, 0, 100, 100)); fdev->initialize(); cs->setOpacity(fdev->data(), OPACITY_OPAQUE_U8, 100 * 100); QPoint errpoint; QImage result(QString(FILES_DATA_DIR) + QDir::separator() + "result_autobrush_1.png"); QImage image = fdev->convertToQImage(0); if (!TestUtil::compareQImages(errpoint, image, result)) { image.save("kis_autobrush_test_1.png"); QFAIL(QString("Failed to create identical image, first different pixel: %1,%2 \n").arg(errpoint.x()).arg(errpoint.y()).toLatin1()); } // Check creating a mask dab with a single color fdev = new KisFixedPaintDevice(cs); a->mask(fdev, KoColor(Qt::black, cs), KisDabShape(), info); result = QImage(QString(FILES_DATA_DIR) + QDir::separator() + "result_autobrush_3.png"); image = fdev->convertToQImage(0); if (!TestUtil::compareQImages(errpoint, image, result)) { image.save("kis_autobrush_test_3.png"); QFAIL(QString("Failed to create identical image, first different pixel: %1,%2 \n").arg(errpoint.x()).arg(errpoint.y()).toLatin1()); } // Check creating a mask dab with a color taken from a paint device KoColor red(Qt::red, cs); cs->setOpacity(red.data(), quint8(128), 1); KisPaintDeviceSP dev = new KisPaintDevice(cs); dev->fill(0, 0, 100, 100, red.data()); fdev = new KisFixedPaintDevice(cs); a->mask(fdev, dev, KisDabShape(), info); result = QImage(QString(FILES_DATA_DIR) + QDir::separator() + "result_autobrush_4.png"); image = fdev->convertToQImage(0); if (!TestUtil::compareQImages(errpoint, image, result)) { image.save("kis_autobrush_test_4.png"); QFAIL(QString("Failed to create identical image, first different pixel: %1,%2 \n").arg(errpoint.x()).arg(errpoint.y()).toLatin1()); } } static void dabSizeHelper(KisBrushSP const& brush, QString const& name, KisDabShape const& shape, int expectedWidth, int expectedHeight) { qDebug() << name; QCOMPARE(brush->maskWidth(shape, 0.0, 0.0, KisPaintInformation()), expectedWidth); QCOMPARE(brush->maskHeight(shape, 0.0, 0.0, KisPaintInformation()), expectedHeight); } void KisAutoBrushTest::testDabSize() { KisCircleMaskGenerator* circle = new KisCircleMaskGenerator(10, 0.5, 1.0, 1.0, 2, false); - KisBrushSP a = new KisAutoBrush(circle, 0.0, 0.0); + KisBrushSP a(new KisAutoBrush(circle, 0.0, 0.0)); QCOMPARE(a->width(), 10); QCOMPARE(a->height(), 5); dabSizeHelper(a, "Identity", KisDabShape(), 10, 5); dabSizeHelper(a, "Double", KisDabShape(2.0, 1.0, 0.0), 20, 10); dabSizeHelper(a, "Halve", KisDabShape(0.5, 1.0, 0.0), 5, 3); dabSizeHelper(a, "180 deg", KisDabShape(1.0, 1.0, M_PI), 10, 5); dabSizeHelper(a, "90 deg", KisDabShape(1.0, 1.0, M_PI_2), 6, 10); // ceil rule dabSizeHelper(a, "-90 deg", KisDabShape(1.0, 1.0, -M_PI_2), 6, 11); // ceil rule dabSizeHelper(a, "45 deg", KisDabShape(1.0, 1.0, 0.25 * M_PI), 11, 11); dabSizeHelper(a, "2x, 45d", KisDabShape(2.0, 1.0, 0.25 * M_PI), 22, 22); dabSizeHelper(a, "0.5x, 45d", KisDabShape(0.5, 1.0, 0.25 * M_PI), 6, 6); dabSizeHelper(a, "0.5x, 45d", KisDabShape(0.5, 1.0, 0.25 * M_PI), 6, 6); dabSizeHelper(a, "0.5y", KisDabShape(1.0, 0.5, 0.0), 10, 5); } //#define SAVE_OUTPUT_IMAGES void KisAutoBrushTest::testCopyMasking() { int w = 64; int h = 64; int x = 0; int y = 0; QRect rc(x, y, w, h); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KoColor black(Qt::black, cs); KoColor red(Qt::red, cs); KisPaintDeviceSP tempDev = new KisPaintDevice(cs); tempDev->fill(0, 0, w, h, red.data()); #ifdef SAVE_OUTPUT_IMAGES tempDev->convertToQImage(0).save("tempDev.png"); #endif KisCircleMaskGenerator * mask = new KisCircleMaskGenerator(w, 1.0, 0.5, 0.5, 2, true); KisAutoBrush brush(mask, 0, 0); KisFixedPaintDeviceSP maskDab = new KisFixedPaintDevice(cs); brush.mask(maskDab, black, KisDabShape(), KisPaintInformation()); maskDab->convertTo(KoColorSpaceRegistry::instance()->alpha8()); #ifdef SAVE_OUTPUT_IMAGES maskDab->convertToQImage(0, 0, 0, 64, 64).save("maskDab.png"); #endif QCOMPARE(tempDev->exactBounds(), rc); QCOMPARE(maskDab->bounds(), rc); KisFixedPaintDeviceSP dev2fixed = new KisFixedPaintDevice(cs); dev2fixed->setRect(rc); dev2fixed->initialize(); tempDev->readBytes(dev2fixed->data(), rc); dev2fixed->convertToQImage(0).save("converted-tempDev-to-fixed.png"); KisPaintDeviceSP dev = new KisPaintDevice(cs); KisPainter painter(dev); painter.setCompositeOp(COMPOSITE_COPY); painter.bltFixedWithFixedSelection(x, y, dev2fixed, maskDab, 0, 0, 0, 0, rc.width(), rc.height()); //painter.bitBltWithFixedSelection(x, y, tempDev, maskDab, 0, 0, 0, 0, rc.width(), rc.height()); #ifdef SAVE_OUTPUT_IMAGES dev->convertToQImage(0).save("final.png"); #endif } void KisAutoBrushTest::testClone() { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisCircleMaskGenerator* circle = new KisCircleMaskGenerator(10, 0.7, 0.85, 0.5, 2, true); - KisBrushSP brush = new KisAutoBrush(circle, 0.5, 0.0); + KisBrushSP brush(new KisAutoBrush(circle, 0.5, 0.0)); KisPaintInformation info(QPointF(100.0, 100.0), 0.5); KisFixedPaintDeviceSP fdev1 = new KisFixedPaintDevice(cs); brush->mask(fdev1, KoColor(Qt::black, cs), KisDabShape(0.8, 1.0, 8.0), info); QImage res1 = fdev1->convertToQImage(0); KisBrushSP clone = brush->clone(); KisFixedPaintDeviceSP fdev2 = new KisFixedPaintDevice(cs); clone->mask(fdev2, KoColor(Qt::black, cs), KisDabShape(0.8, 1.0, 8.0), info); QImage res2 = fdev2->convertToQImage(0); QCOMPARE(res1, res2); } QTEST_MAIN(KisAutoBrushTest) diff --git a/libs/brush/tests/kis_imagepipe_brush_test.cpp b/libs/brush/tests/kis_imagepipe_brush_test.cpp index 6fabb72275..e7b340baa6 100644 --- a/libs/brush/tests/kis_imagepipe_brush_test.cpp +++ b/libs/brush/tests/kis_imagepipe_brush_test.cpp @@ -1,264 +1,264 @@ /* * Copyright (c) 2012 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_imagepipe_brush_test.h" #include #include #include #include #include #include #include #include #include "kis_imagepipe_brush.h" #include #include #define COMPARE_ALL(brush, method) \ - Q_FOREACH (KisGbrBrush *child, brush->brushes()) { \ + Q_FOREACH (KisGbrBrushSP child, brush->brushes()) { \ if(brush->method() != child->method()) { \ dbgKrita << "Failing method:" << #method \ << "brush index:" \ << brush->brushes().indexOf(child); \ QCOMPARE(brush->method(), child->method()); \ } \ } -inline void KisImagePipeBrushTest::checkConsistency(KisImagePipeBrush *brush) +inline void KisImagePipeBrushTest::checkConsistency(KisImagePipeBrushSP brush) { qreal scale = 0.5; Q_UNUSED(scale); - KisGbrBrush *firstBrush = brush->brushes().first(); + KisGbrBrushSP firstBrush = brush->brushes().first(); /** * This set of values is supposed to be constant, so * it is just set to the corresponding values of the * first brush */ QCOMPARE(brush->width(), firstBrush->width()); QCOMPARE(brush->height(), firstBrush->height()); QCOMPARE(brush->boundary(), firstBrush->boundary()); /** * These values should be spread over the children brushes */ COMPARE_ALL(brush, maskAngle); COMPARE_ALL(brush, scale); COMPARE_ALL(brush, angle); COMPARE_ALL(brush, spacing); /** * Check mask size values, they depend on current brush */ KisPaintInformation info; - KisBrush *oldBrush = brush->testingGetCurrentBrush(info); + KisBrushSP oldBrush = brush->testingGetCurrentBrush(info); QVERIFY(oldBrush); qreal realScale = 1; qreal realAngle = 0; qreal subPixelX = 0; qreal subPixelY = 0; int maskWidth = brush->maskWidth(KisDabShape(realScale, 1.0, realAngle), subPixelX, subPixelY, info); int maskHeight = brush->maskHeight(KisDabShape(realScale, 1.0, realAngle), subPixelX, subPixelY, info); const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8(); KisFixedPaintDeviceSP dev = brush->testingGetCurrentBrush(info)->paintDevice( cs, KisDabShape(realScale, 1.0, realAngle), info, subPixelX, subPixelY); QCOMPARE(maskWidth, dev->bounds().width()); QCOMPARE(maskHeight, dev->bounds().height()); - KisBrush *newBrush = brush->testingGetCurrentBrush(info); + KisBrushSP newBrush = brush->testingGetCurrentBrush(info); QCOMPARE(oldBrush, newBrush); } void KisImagePipeBrushTest::testLoading() { - QScopedPointer brush(new KisImagePipeBrush(QString(FILES_DATA_DIR) + QDir::separator() + "C_Dirty_Spot.gih")); + QSharedPointer brush(new KisImagePipeBrush(QString(FILES_DATA_DIR) + QDir::separator() + "C_Dirty_Spot.gih")); brush->load(); QVERIFY(brush->valid()); - checkConsistency(brush.data()); + checkConsistency(brush); } void KisImagePipeBrushTest::testChangingBrushes() { - QScopedPointer brush(new KisImagePipeBrush(QString(FILES_DATA_DIR) + QDir::separator() + "C_Dirty_Spot.gih")); + QSharedPointer brush(new KisImagePipeBrush(QString(FILES_DATA_DIR) + QDir::separator() + "C_Dirty_Spot.gih")); brush->load(); QVERIFY(brush->valid()); qreal rotation = 0; KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, rotation); for (int i = 0; i < 100; i++) { - checkConsistency(brush.data()); + checkConsistency(brush); brush->testingSelectNextBrush(info); } } -void checkIncrementalPainting(KisBrush *brush, const QString &prefix) +void checkIncrementalPainting(KisBrushSP brush, const QString &prefix) { qreal realScale = 1; qreal realAngle = 0; const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); KoColor fillColor(Qt::red, cs); KisFixedPaintDeviceSP fixedDab = new KisFixedPaintDevice(cs); qreal rotation = 0; qreal subPixelX = 0.0; qreal subPixelY = 0.0; KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, rotation); for (int i = 0; i < 20; i++) { int maskWidth = brush->maskWidth(KisDabShape(realScale, 1.0, realAngle), subPixelX, subPixelY, info); int maskHeight = brush->maskHeight(KisDabShape(realScale, 1.0, realAngle), subPixelX, subPixelY, info); QRect fillRect(0, 0, maskWidth, maskHeight); fixedDab->setRect(fillRect); fixedDab->lazyGrowBufferWithoutInitialization(); brush->mask(fixedDab, fillColor, KisDabShape(realScale, 1.0, realAngle), info); QCOMPARE(fixedDab->bounds(), fillRect); QImage result = fixedDab->convertToQImage(0); result.save(QString("fixed_dab_%1_%2.png").arg(prefix).arg(i)); } } void KisImagePipeBrushTest::testSimpleDabApplication() { - QScopedPointer brush(new KisImagePipeBrush(QString(FILES_DATA_DIR) + QDir::separator() + "C_Dirty_Spot.gih")); + QSharedPointer brush(new KisImagePipeBrush(QString(FILES_DATA_DIR) + QDir::separator() + "C_Dirty_Spot.gih")); brush->load(); QVERIFY(brush->valid()); - checkConsistency(brush.data()); - checkIncrementalPainting(brush.data(), "simple"); + checkConsistency(brush); + checkIncrementalPainting(brush, "simple"); } void KisImagePipeBrushTest::testColoredDab() { - QScopedPointer brush(new KisImagePipeBrush(QString(FILES_DATA_DIR) + QDir::separator() + "G_Sparks.gih")); + QSharedPointer brush(new KisImagePipeBrush(QString(FILES_DATA_DIR) + QDir::separator() + "G_Sparks.gih")); brush->load(); QVERIFY(brush->valid()); - checkConsistency(brush.data()); + checkConsistency(brush); QCOMPARE(brush->useColorAsMask(), false); QCOMPARE(brush->hasColor(), true); QCOMPARE(brush->brushType(), PIPE_IMAGE); // let it be the mask (should be revertible) brush->setUseColorAsMask(true); QCOMPARE(brush->useColorAsMask(), true); QCOMPARE(brush->hasColor(), true); QCOMPARE(brush->brushType(), PIPE_MASK); // revert back brush->setUseColorAsMask(false); QCOMPARE(brush->useColorAsMask(), false); QCOMPARE(brush->hasColor(), true); QCOMPARE(brush->brushType(), PIPE_IMAGE); // convert to the mask (irreversible) brush->makeMaskImage(); QCOMPARE(brush->useColorAsMask(), false); QCOMPARE(brush->hasColor(), false); QCOMPARE(brush->brushType(), PIPE_MASK); - checkConsistency(brush.data()); + checkConsistency(brush); } void KisImagePipeBrushTest::testColoredDabWash() { - QScopedPointer brush(new KisImagePipeBrush(QString(FILES_DATA_DIR) + QDir::separator() + "G_Sparks.gih")); + QSharedPointer brush(new KisImagePipeBrush(QString(FILES_DATA_DIR) + QDir::separator() + "G_Sparks.gih")); brush->load(); QVERIFY(brush->valid()); const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); qreal rotation = 0; KisPaintInformation info(QPointF(100.0, 100.0), 0.5, 0, 0, rotation); KisPaintDeviceSP layer = new KisPaintDevice(cs); KisPainter painter(layer); painter.setCompositeOp(COMPOSITE_ALPHA_DARKEN); - const QVector gbrs = brush->brushes(); + const QVector gbrs = brush->brushes(); KisFixedPaintDeviceSP dab = gbrs.at(0)->paintDevice(cs, KisDabShape(2.0, 1.0, 0.0), info); painter.bltFixed(0, 0, dab, 0, 0, dab->bounds().width(), dab->bounds().height()); painter.bltFixed(80, 60, dab, 0, 0, dab->bounds().width(), dab->bounds().height()); painter.end(); QRect rc = layer->exactBounds(); QImage result = layer->convertToQImage(0, rc.x(), rc.y(), rc.width(), rc.height()); #if 0 // if you want to see the result on white background, set #if 1 QImage bg(result.size(), result.format()); bg.fill(Qt::white); QPainter qPainter(&bg); qPainter.drawImage(0, 0, result); result = bg; #endif result.save("z_spark_alpha_darken.png"); } #include "kis_text_brush.h" void KisImagePipeBrushTest::testTextBrushNoPipes() { - QScopedPointer brush(new KisTextBrush()); + QSharedPointer brush(new KisTextBrush()); brush->setPipeMode(false); brush->setFont(QApplication::font()); brush->setText("The_Quick_Brown_Fox_Jumps_Over_The_Lazy_Dog"); brush->updateBrush(); - checkIncrementalPainting(brush.data(), "text_no_incremental"); + checkIncrementalPainting(brush, "text_no_incremental"); } void KisImagePipeBrushTest::testTextBrushPiped() { - QScopedPointer brush(new KisTextBrush()); + QSharedPointer brush(new KisTextBrush()); brush->setPipeMode(true); brush->setFont(QApplication::font()); brush->setText("The_Quick_Brown_Fox_Jumps_Over_The_Lazy_Dog"); brush->updateBrush(); - checkIncrementalPainting(brush.data(), "text_incremental"); + checkIncrementalPainting(brush, "text_incremental"); } QTEST_MAIN(KisImagePipeBrushTest) diff --git a/libs/brush/tests/kis_imagepipe_brush_test.h b/libs/brush/tests/kis_imagepipe_brush_test.h index e5da39636c..850bd2d23d 100644 --- a/libs/brush/tests/kis_imagepipe_brush_test.h +++ b/libs/brush/tests/kis_imagepipe_brush_test.h @@ -1,42 +1,42 @@ /* * Copyright (c) 2012 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. */ #ifndef __KIS_IMAGEPIPE_BRUSH_TEST_H #define __KIS_IMAGEPIPE_BRUSH_TEST_H #include -class KisImagePipeBrush; +#include class KisImagePipeBrushTest : public QObject { Q_OBJECT private Q_SLOTS: void testLoading(); void testChangingBrushes(); void testSimpleDabApplication(); void testColoredDab(); void testColoredDabWash(); void testTextBrushNoPipes(); void testTextBrushPiped(); private: - void checkConsistency(KisImagePipeBrush *brush); + void checkConsistency(KisImagePipeBrushSP brush); }; #endif /* __KIS_IMAGEPIPE_BRUSH_TEST_H */ diff --git a/libs/flake/resources/KoGamutMask.h b/libs/flake/resources/KoGamutMask.h index 5c54c15bd7..2fae84593f 100644 --- a/libs/flake/resources/KoGamutMask.h +++ b/libs/flake/resources/KoGamutMask.h @@ -1,100 +1,102 @@ /* * Copyright (c) 2018 Anna Medonosova * * 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; version 2.1 of the License. * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KOGAMUTMASK_H #define KOGAMUTMASK_H #include #include #include #include #include #include #include #include #include class KoViewConverter; class KoGamutMaskShape { public: KoGamutMaskShape(KoShape* shape); KoGamutMaskShape(); ~KoGamutMaskShape(); bool coordIsClear(const QPointF& coord, const KoViewConverter& viewConverter, int maskRotation) const; QPainterPath outline(); void paint(QPainter &painter, const KoViewConverter& viewConverter, int maskRotation); void paintStroke(QPainter &painter, const KoViewConverter& viewConverter, int maskRotation); KoShape* koShape(); private: KoShape* m_maskShape; KoShapePaintingContext m_shapePaintingContext; }; /** * @brief The resource type for gamut masks used by the artistic color selector */ class KRITAFLAKE_EXPORT KoGamutMask : public QObject, public KoResource { Q_OBJECT public: KoGamutMask(const QString &filename); KoGamutMask(); KoGamutMask(KoGamutMask *rhs); bool coordIsClear(const QPointF& coord, KoViewConverter& viewConverter, bool preview); bool load() override __attribute__((optimize(0))); bool loadFromDevice(QIODevice *dev) override; bool save() override; bool saveToDevice(QIODevice* dev) const override; void paint(QPainter &painter, KoViewConverter& viewConverter, bool preview); void paintStroke(QPainter &painter, KoViewConverter& viewConverter, bool preview); QString title(); void setTitle(QString title); QString description(); void setDescription(QString description); int rotation(); void setRotation(int rotation); QSizeF maskSize(); void setMaskShapes(QList shapes); void setPreviewMaskShapes(QList shapes); QList koShapes() const; void clearPreview(); private: void setMaskShapesToVector(QList shapes, QVector& targetVector); struct Private; Private* const d; }; +typedef QSharedPointer KoGamutMaskSP; + #endif // KOGAMUTMASK_H diff --git a/libs/image/brushengine/kis_locked_properties_proxy.cpp b/libs/image/brushengine/kis_locked_properties_proxy.cpp index c25abff634..b057eb1049 100644 --- a/libs/image/brushengine/kis_locked_properties_proxy.cpp +++ b/libs/image/brushengine/kis_locked_properties_proxy.cpp @@ -1,115 +1,115 @@ /* * Copyright (c) 2014 Dmitry Kazakov * Copyright (c) 2014 Mohit Goyal * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include KisLockedPropertiesProxy::KisLockedPropertiesProxy(KisPropertiesConfiguration *p, KisLockedPropertiesSP l) { m_parent = p; m_lockedProperties = l; } KisLockedPropertiesProxy::~KisLockedPropertiesProxy() { } QVariant KisLockedPropertiesProxy::getProperty(const QString &name) const { KisPaintOpSettings *t = dynamic_cast(m_parent); if (!t->preset()) return m_parent->getProperty(name); // restores the dirty state on returns automagically - KisPaintOpPreset::DirtyStateSaver dirtyStateSaver(t->preset().data()); + KisPaintOpPreset::DirtyStateSaver dirtyStateSaver(t->preset()); if (m_lockedProperties->lockedProperties()) { if (m_lockedProperties->lockedProperties()->hasProperty(name)) { KisLockedPropertiesServer::instance()->setPropertiesFromLocked(true); if (!m_parent->hasProperty(name + "_previous")) { m_parent->setProperty(name + "_previous", m_parent->getProperty(name)); } m_parent->setProperty(name, m_lockedProperties->lockedProperties()->getProperty(name)); return m_lockedProperties->lockedProperties()->getProperty(name); } else { if (m_parent->hasProperty(name + "_previous")) { m_parent->setProperty(name, m_parent->getProperty(name + "_previous")); m_parent->removeProperty(name + "_previous"); } } } return m_parent->getProperty(name); } void KisLockedPropertiesProxy::setProperty(const QString & name, const QVariant & value) { KisPaintOpSettings *t = dynamic_cast(m_parent); if (!t->preset()) return; if (m_lockedProperties->lockedProperties()) { if (m_lockedProperties->lockedProperties()->hasProperty(name)) { m_lockedProperties->lockedProperties()->setProperty(name, value); m_parent->setProperty(name, value); if (!m_parent->hasProperty(name + "_previous")) { // restores the dirty state on returns automagically - KisPaintOpPreset::DirtyStateSaver dirtyStateSaver(t->preset().data()); + KisPaintOpPreset::DirtyStateSaver dirtyStateSaver(t->preset()); m_parent->setProperty(name + "_previous", m_parent->getProperty(name)); } return; } } m_parent->setProperty(name, value); } bool KisLockedPropertiesProxy::hasProperty(const QString &name) const { KisPaintOpSettings *t = dynamic_cast(m_parent); if (!t->preset()) return m_parent->hasProperty(name); return (m_lockedProperties->lockedProperties() && m_lockedProperties->lockedProperties()->hasProperty(name)) || m_parent->hasProperty(name); } QList KisLockedPropertiesProxy::getPropertiesKeys() const { KisPaintOpSettings *t = dynamic_cast(m_parent); if (!t->preset()) return m_parent->getPropertiesKeys(); QList result = m_parent->getPropertiesKeys(); if (m_lockedProperties->lockedProperties()) { QSet properties = QSet::fromList(result); properties += QSet::fromList(m_lockedProperties->lockedProperties()->getPropertiesKeys()); result = properties.toList(); } return result; } diff --git a/libs/image/brushengine/kis_paintop_preset.cpp b/libs/image/brushengine/kis_paintop_preset.cpp index f8785ae7a6..f81d1a08e1 100644 --- a/libs/image/brushengine/kis_paintop_preset.cpp +++ b/libs/image/brushengine/kis_paintop_preset.cpp @@ -1,425 +1,426 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * Copyright (C) Sven Langkamp , (C) 2009 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. 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 "kis_paintop_registry.h" #include "kis_painter.h" #include #include "kis_paint_device.h" #include "kis_image.h" #include "kis_paintop_settings_update_proxy.h" #include #include struct Q_DECL_HIDDEN KisPaintOpPreset::Private { Private() : settings(0), dirtyPreset(false) { } KisPaintOpSettingsSP settings; bool dirtyPreset; QScopedPointer updateProxy; }; KisPaintOpPreset::KisPaintOpPreset() : KoResource(QString()) , m_d(new Private) { } KisPaintOpPreset::KisPaintOpPreset(const QString & fileName) : KoResource(fileName) , m_d(new Private) { } KisPaintOpPreset::~KisPaintOpPreset() { delete m_d; } KisPaintOpPresetSP KisPaintOpPreset::clone() const { KisPaintOpPresetSP preset(new KisPaintOpPreset()); if (settings()) { preset->setSettings(settings()); // the settings are cloned inside! } preset->setPresetDirty(isPresetDirty()); // only valid if we could clone the settings preset->setValid(settings()); preset->setPaintOp(paintOp()); preset->setName(name()); preset->setImage(image()); preset->settings()->setPreset(KisPaintOpPresetWSP(preset)); Q_ASSERT(preset->valid()); return preset; } void KisPaintOpPreset::setPresetDirty(bool value) { m_d->dirtyPreset = value; } bool KisPaintOpPreset::isPresetDirty() const { return m_d->dirtyPreset; } void KisPaintOpPreset::setPaintOp(const KoID & paintOp) { Q_ASSERT(m_d->settings); m_d->settings->setProperty("paintop", paintOp.id()); } KoID KisPaintOpPreset::paintOp() const { Q_ASSERT(m_d->settings); return KoID(m_d->settings->getString("paintop")); } void KisPaintOpPreset::setOptionsWidget(KisPaintOpConfigWidget* widget) { if (m_d->settings) { m_d->settings->setOptionsWidget(widget); if (widget) { widget->setConfigurationSafe(m_d->settings); } } } void KisPaintOpPreset::setSettings(KisPaintOpSettingsSP settings) { Q_ASSERT(settings); Q_ASSERT(!settings->getString("paintop", QString()).isEmpty()); DirtyStateSaver dirtyStateSaver(this); KisPaintOpConfigWidget *oldOptionsWidget = 0; if (m_d->settings) { oldOptionsWidget = m_d->settings->optionsWidget(); m_d->settings->setOptionsWidget(0); - m_d->settings->setPreset(0); + m_d->settings->setPreset(QWeakPointer()); m_d->settings = 0; } if (settings) { m_d->settings = settings->clone(); - m_d->settings->setPreset(KisPaintOpPresetWSP(this)); + QSharedPointer sp(this); + m_d->settings->setPreset(QWeakPointer(sp)); if (oldOptionsWidget) { m_d->settings->setOptionsWidget(oldOptionsWidget); oldOptionsWidget->setConfigurationSafe(m_d->settings); } } setValid(m_d->settings); if (m_d->updateProxy) { m_d->updateProxy->notifyUniformPropertiesChanged(); m_d->updateProxy->notifySettingsChanged(); } } KisPaintOpSettingsSP KisPaintOpPreset::settings() const { Q_ASSERT(m_d->settings); Q_ASSERT(!m_d->settings->getString("paintop", QString()).isEmpty()); return m_d->settings; } bool KisPaintOpPreset::load() { dbgImage << "Load preset " << filename(); setValid(false); if (filename().isEmpty()) { return false; } QIODevice *dev = 0; QByteArray ba; if (filename().startsWith("bundle://")) { QString bn = filename().mid(9); int pos = bn.lastIndexOf(":"); QString fn = bn.right(bn.size() - pos - 1); bn = bn.left(pos); QScopedPointer resourceStore(KoStore::createStore(bn, KoStore::Read, "application/x-krita-resourcebundle", KoStore::Zip)); if (!resourceStore || resourceStore->bad()) { warnKrita << "Could not open store on bundle" << bn; return false; } if (resourceStore->isOpen()) resourceStore->close(); if (!resourceStore->open(fn)) { warnKrita << "Could not open preset" << fn << "in bundle" << bn; return false; } ba = resourceStore->device()->readAll(); dev = new QBuffer(&ba); resourceStore->close(); } else { dev = new QFile(filename()); if (dev->size() == 0) { delete dev; return false; } if (!dev->open(QIODevice::ReadOnly)) { warnKrita << "Can't open file " << filename(); delete dev; return false; } } bool res = loadFromDevice(dev); delete dev; setValid(res); setPresetDirty(false); return res; } bool KisPaintOpPreset::loadFromDevice(QIODevice *dev) { QImageReader reader(dev, "PNG"); QString version = reader.text("version"); QString preset = reader.text("preset"); dbgImage << version; if (version != "2.2") { return false; } QImage img; if (!reader.read(&img)) { dbgImage << "Fail to decode PNG"; return false; } //Workaround for broken presets //Presets was saved with nested cdata section preset.replace(""); preset.replace("]]>", ""); QDomDocument doc; if (!doc.setContent(preset)) { return false; } fromXML(doc.documentElement()); if (!m_d->settings) { return false; } setValid(true); setImage(img); return true; } bool KisPaintOpPreset::save() { if (filename().isEmpty()) return false; QString paintopid = m_d->settings->getString("paintop", QString()); if (paintopid.isEmpty()) return false; QFile f(filename()); f.open(QFile::WriteOnly); return saveToDevice(&f); } void KisPaintOpPreset::toXML(QDomDocument& doc, QDomElement& elt) const { QString paintopid = m_d->settings->getString("paintop", QString()); elt.setAttribute("paintopid", paintopid); elt.setAttribute("name", name()); // sanitize the settings bool hasTexture = m_d->settings->getBool("Texture/Pattern/Enabled"); if (!hasTexture) { Q_FOREACH (const QString & key, m_d->settings->getProperties().keys()) { if (key.startsWith("Texture") && key != "Texture/Pattern/Enabled") { m_d->settings->removeProperty(key); } } } m_d->settings->toXML(doc, elt); } void KisPaintOpPreset::fromXML(const QDomElement& presetElt) { setName(presetElt.attribute("name")); QString paintopid = presetElt.attribute("paintopid"); if (paintopid.isEmpty()) { dbgImage << "No paintopid attribute"; setValid(false); return; } if (KisPaintOpRegistry::instance()->get(paintopid) == 0) { dbgImage << "No paintop " << paintopid; setValid(false); return; } KoID id(paintopid, QString()); KisPaintOpSettingsSP settings = KisPaintOpRegistry::instance()->settings(id); if (!settings) { setValid(false); warnKrita << "Could not load settings for preset" << paintopid; return; } settings->fromXML(presetElt); // sanitize the settings bool hasTexture = settings->getBool("Texture/Pattern/Enabled"); if (!hasTexture) { Q_FOREACH (const QString & key, settings->getProperties().keys()) { if (key.startsWith("Texture") && key != "Texture/Pattern/Enabled") { settings->removeProperty(key); } } } setSettings(settings); } bool KisPaintOpPreset::saveToDevice(QIODevice *dev) const { QImageWriter writer(dev, "PNG"); QDomDocument doc; QDomElement root = doc.createElement("Preset"); toXML(doc, root); doc.appendChild(root); writer.setText("version", "2.2"); writer.setText("preset", doc.toString()); QImage img; if (image().isNull()) { img = QImage(1, 1, QImage::Format_RGB32); } else { img = image(); } m_d->dirtyPreset = false; KoResource::saveToDevice(dev); return writer.write(img); } KisPaintopSettingsUpdateProxy* KisPaintOpPreset::updateProxy() const { if (!m_d->updateProxy) { m_d->updateProxy.reset(new KisPaintopSettingsUpdateProxy()); } return m_d->updateProxy.data(); } KisPaintopSettingsUpdateProxy* KisPaintOpPreset::updateProxyNoCreate() const { return m_d->updateProxy.data(); } QList KisPaintOpPreset::uniformProperties() { return m_d->settings->uniformProperties(m_d->settings); } bool KisPaintOpPreset::hasMaskingPreset() const { return m_d->settings && m_d->settings->hasMaskingSettings(); } KisPaintOpPresetSP KisPaintOpPreset::createMaskingPreset() const { KisPaintOpPresetSP result; if (m_d->settings && m_d->settings->hasMaskingSettings()) { - result = new KisPaintOpPreset(); + result.reset(new KisPaintOpPreset()); result->setSettings(m_d->settings->createMaskingSettings()); if (!result->valid()) { result.clear(); } } return result; } -KisPaintOpPreset::UpdatedPostponer::UpdatedPostponer(KisPaintOpPreset *preset) +KisPaintOpPreset::UpdatedPostponer::UpdatedPostponer(KisPaintOpPresetSP preset) : m_updateProxy(preset->updateProxyNoCreate()) { if (m_updateProxy) { m_updateProxy->postponeSettingsChanges(); } } KisPaintOpPreset::UpdatedPostponer::~UpdatedPostponer() { if (m_updateProxy) { m_updateProxy->unpostponeSettingsChanges(); } } diff --git a/libs/image/brushengine/kis_paintop_preset.h b/libs/image/brushengine/kis_paintop_preset.h index 1b554435a5..cf42a6d2fc 100644 --- a/libs/image/brushengine/kis_paintop_preset.h +++ b/libs/image/brushengine/kis_paintop_preset.h @@ -1,151 +1,166 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KIS_PAINTOP_PRESET_H #define KIS_PAINTOP_PRESET_H #include #include "KoID.h" #include "kis_types.h" #include "kis_shared.h" #include "kritaimage_export.h" #include class KisPaintopSettingsUpdateProxy; class KisPaintOpConfigWidget; /** * A KisPaintOpPreset contains a particular set of settings * associated with a paintop, like brush, paintopsettings. * A new property in this class is to make it dirty. That means the * user can now temporarily save any tweaks in the Preset throughout * the session. The Dirty Preset setting/unsetting is handled by KisPaintOpPresetSettings */ -class KRITAIMAGE_EXPORT KisPaintOpPreset : public KoResource, public KisShared +class KRITAIMAGE_EXPORT KisPaintOpPreset : public KoResource { public: KisPaintOpPreset(); KisPaintOpPreset(const QString& filename); ~KisPaintOpPreset() override; KisPaintOpPresetSP clone() const; /// set the id of the paintop plugin void setPaintOp(const KoID & paintOp); /// return the id of the paintop plugin KoID paintOp() const; /// replace the current settings object with the specified settings void setSettings(KisPaintOpSettingsSP settings); void setOriginalSettings(KisPaintOpSettingsSP originalSettings); /// return the settings that define this paintop preset KisPaintOpSettingsSP settings() const; KisPaintOpSettingsSP originalSettings() const; bool load() override; bool loadFromDevice(QIODevice *dev) override; bool save() override; bool saveToDevice(QIODevice* dev) const override; void toXML(QDomDocument& doc, QDomElement& elt) const; void fromXML(const QDomElement& elt); bool removable() const { return true; } QString defaultFileExtension() const override { return ".kpp"; } void setPresetDirty(bool value); bool isPresetDirty() const; /** * Never use manual save/restore calls to * isPresetDirty()/setPresetDirty()! They will lead to * hard-to-tack-down bugs when the dirty state will not be * restored on jumps like 'return', 'break' or exception. */ class KRITAIMAGE_EXPORT DirtyStateSaver { public: + DirtyStateSaver(KisPaintOpPresetSP preset) + : m_preset(preset) + , m_isDirty(preset->isPresetDirty()) + { + } + + + /// Extra constructor to be called from KisPaintOpPreset itself DirtyStateSaver(KisPaintOpPreset *preset) - : m_preset(preset), m_isDirty(preset->isPresetDirty()) + : m_parentPreset(preset) + , m_isDirty(preset->isPresetDirty()) { } ~DirtyStateSaver() { - m_preset->setPresetDirty(m_isDirty); + if (m_preset) { + m_preset->setPresetDirty(m_isDirty); + } + else if (m_parentPreset) { + m_parentPreset->setPresetDirty(m_isDirty); + } } private: - KisPaintOpPreset *m_preset; + KisPaintOpPresetSP m_preset; + KisPaintOpPreset *m_parentPreset; bool m_isDirty; }; /** * @brief The UpdatedPostponer class * @see KisPaintopSettingsUpdateProxy::postponeSettingsChanges() */ class KRITAIMAGE_EXPORT UpdatedPostponer{ public: - UpdatedPostponer(KisPaintOpPreset *preset); + UpdatedPostponer(KisPaintOpPresetSP preset); ~UpdatedPostponer(); private: KisPaintopSettingsUpdateProxy *m_updateProxy; }; void setOptionsWidget(KisPaintOpConfigWidget *widget); KisPaintopSettingsUpdateProxy* updateProxy() const; KisPaintopSettingsUpdateProxy* updateProxyNoCreate() const; QList uniformProperties(); /** * @return true if this preset demands a secondary masked brush running * alongside it */ bool hasMaskingPreset() const; /** * @return a newly created preset of the masked brush that should be run * alongside the current brush */ KisPaintOpPresetSP createMaskingPreset() const; private: struct Private; Private * const m_d; }; Q_DECLARE_METATYPE(KisPaintOpPresetSP) #endif diff --git a/libs/image/brushengine/kis_paintop_settings.cpp b/libs/image/brushengine/kis_paintop_settings.cpp index 95405f2621..e9a400abe2 100644 --- a/libs/image/brushengine/kis_paintop_settings.cpp +++ b/libs/image/brushengine/kis_paintop_settings.cpp @@ -1,524 +1,526 @@ /* * Copyright (c) 2007 Boudewijn Rempt * Copyright (c) 2008 Lukáš Tvrdý * Copyright (c) 2014 Mohit Goyal * 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 #include #include #include #include #include #include #include #include "kis_paint_layer.h" #include "kis_image.h" #include "kis_painter.h" #include "kis_paint_device.h" #include "kis_paintop_registry.h" #include "kis_timing_information.h" #include #include "kis_paintop_config_widget.h" #include #include "kis_paintop_settings_update_proxy.h" #include #include #include #include #include #include "KisPaintopSettingsIds.h" struct Q_DECL_HIDDEN KisPaintOpSettings::Private { Private() : disableDirtyNotifications(false) {} QPointer settingsWidget; QString modelName; KisPaintOpPresetWSP preset; QList uniformProperties; bool disableDirtyNotifications; class DirtyNotificationsLocker { public: DirtyNotificationsLocker(KisPaintOpSettings::Private *d) : m_d(d), m_oldNotificationsState(d->disableDirtyNotifications) { m_d->disableDirtyNotifications = true; } ~DirtyNotificationsLocker() { m_d->disableDirtyNotifications = m_oldNotificationsState; } private: KisPaintOpSettings::Private *m_d; bool m_oldNotificationsState; Q_DISABLE_COPY(DirtyNotificationsLocker) }; KisPaintopSettingsUpdateProxy* updateProxyNoCreate() const { auto presetSP = preset.toStrongRef(); return presetSP ? presetSP->updateProxyNoCreate() : 0; } KisPaintopSettingsUpdateProxy* updateProxyCreate() const { auto presetSP = preset.toStrongRef(); return presetSP ? presetSP->updateProxy() : 0; } }; KisPaintOpSettings::KisPaintOpSettings() : d(new Private) { d->preset = 0; } KisPaintOpSettings::~KisPaintOpSettings() { } KisPaintOpSettings::KisPaintOpSettings(const KisPaintOpSettings &rhs) : KisPropertiesConfiguration(rhs) , d(new Private) { d->settingsWidget = 0; d->preset = rhs.preset(); d->modelName = rhs.modelName(); } void KisPaintOpSettings::setOptionsWidget(KisPaintOpConfigWidget* widget) { d->settingsWidget = widget; } + void KisPaintOpSettings::setPreset(KisPaintOpPresetWSP preset) { d->preset = preset; } + KisPaintOpPresetWSP KisPaintOpSettings::preset() const { return d->preset; } bool KisPaintOpSettings::mousePressEvent(const KisPaintInformation &paintInformation, Qt::KeyboardModifiers modifiers, KisNodeWSP currentNode) { Q_UNUSED(modifiers); Q_UNUSED(currentNode); setRandomOffset(paintInformation); return true; // ignore the event by default } void KisPaintOpSettings::setRandomOffset(const KisPaintInformation &paintInformation) { if (getBool("Texture/Pattern/Enabled")) { if (getBool("Texture/Pattern/isRandomOffsetX")) { setProperty("Texture/Pattern/OffsetX", paintInformation.randomSource()->generate(0, KisPropertiesConfiguration::getInt("Texture/Pattern/MaximumOffsetX"))); } if (getBool("Texture/Pattern/isRandomOffsetY")) { setProperty("Texture/Pattern/OffsetY", paintInformation.randomSource()->generate(0, KisPropertiesConfiguration::getInt("Texture/Pattern/MaximumOffsetY"))); } } } bool KisPaintOpSettings::hasMaskingSettings() const { return getBool(KisPaintOpUtils::MaskingBrushEnabledTag, false); } KisPaintOpSettingsSP KisPaintOpSettings::createMaskingSettings() const { if (!hasMaskingSettings()) return KisPaintOpSettingsSP(); const KoID pixelBrushId(KisPaintOpUtils::MaskingBrushPaintOpId, QString()); KisPaintOpSettingsSP maskingSettings = KisPaintOpRegistry::instance()->settings(pixelBrushId); this->getPrefixedProperties(KisPaintOpUtils::MaskingBrushPresetPrefix, maskingSettings); const bool useMasterSize = this->getBool(KisPaintOpUtils::MaskingBrushUseMasterSizeTag, true); if (useMasterSize) { const qreal masterSizeCoeff = getDouble(KisPaintOpUtils::MaskingBrushMasterSizeCoeffTag, 1.0); maskingSettings->setPaintOpSize(masterSizeCoeff * paintOpSize()); } return maskingSettings; } QString KisPaintOpSettings::maskingBrushCompositeOp() const { return getString(KisPaintOpUtils::MaskingBrushCompositeOpTag, COMPOSITE_MULT); } KisPaintOpSettingsSP KisPaintOpSettings::clone() const { QString paintopID = getString("paintop"); if (paintopID.isEmpty()) return 0; KisPaintOpSettingsSP settings = KisPaintOpRegistry::instance()->settings(KoID(paintopID)); QMapIterator i(getProperties()); while (i.hasNext()) { i.next(); settings->setProperty(i.key(), QVariant(i.value())); } settings->setPreset(this->preset()); return settings; } void KisPaintOpSettings::resetSettings(const QStringList &preserveProperties) { QStringList allKeys = preserveProperties; allKeys << "paintop"; QHash preserved; Q_FOREACH (const QString &key, allKeys) { if (hasProperty(key)) { preserved[key] = getProperty(key); } } clearProperties(); for (auto it = preserved.constBegin(); it != preserved.constEnd(); ++it) { setProperty(it.key(), it.value()); } } void KisPaintOpSettings::activate() { } void KisPaintOpSettings::setPaintOpOpacity(qreal value) { KisLockedPropertiesProxySP proxy( KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this)); proxy->setProperty("OpacityValue", value); } void KisPaintOpSettings::setPaintOpFlow(qreal value) { KisLockedPropertiesProxySP proxy( KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this)); proxy->setProperty("FlowValue", value); } void KisPaintOpSettings::setPaintOpCompositeOp(const QString &value) { KisLockedPropertiesProxySP proxy( KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this)); proxy->setProperty("CompositeOp", value); } qreal KisPaintOpSettings::paintOpOpacity() { KisLockedPropertiesProxySP proxy = KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this); return proxy->getDouble("OpacityValue", 1.0); } qreal KisPaintOpSettings::paintOpFlow() { KisLockedPropertiesProxySP proxy( KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this)); return proxy->getDouble("FlowValue", 1.0); } QString KisPaintOpSettings::paintOpCompositeOp() { KisLockedPropertiesProxySP proxy( KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this)); return proxy->getString("CompositeOp", COMPOSITE_OVER); } void KisPaintOpSettings::setEraserMode(bool value) { KisLockedPropertiesProxySP proxy( KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this)); proxy->setProperty("EraserMode", value); } bool KisPaintOpSettings::eraserMode() { KisLockedPropertiesProxySP proxy( KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(this)); return proxy->getBool("EraserMode", false); } QString KisPaintOpSettings::effectivePaintOpCompositeOp() { return !eraserMode() ? paintOpCompositeOp() : COMPOSITE_ERASE; } qreal KisPaintOpSettings::savedEraserSize() const { return getDouble("SavedEraserSize", 0.0); } void KisPaintOpSettings::setSavedEraserSize(qreal value) { setProperty("SavedEraserSize", value); setPropertyNotSaved("SavedEraserSize"); } qreal KisPaintOpSettings::savedBrushSize() const { return getDouble("SavedBrushSize", 0.0); } void KisPaintOpSettings::setSavedBrushSize(qreal value) { setProperty("SavedBrushSize", value); setPropertyNotSaved("SavedBrushSize"); } qreal KisPaintOpSettings::savedEraserOpacity() const { return getDouble("SavedEraserOpacity", 0.0); } void KisPaintOpSettings::setSavedEraserOpacity(qreal value) { setProperty("SavedEraserOpacity", value); setPropertyNotSaved("SavedEraserOpacity"); } qreal KisPaintOpSettings::savedBrushOpacity() const { return getDouble("SavedBrushOpacity", 0.0); } void KisPaintOpSettings::setSavedBrushOpacity(qreal value) { setProperty("SavedBrushOpacity", value); setPropertyNotSaved("SavedBrushOpacity"); } QString KisPaintOpSettings::modelName() const { return d->modelName; } void KisPaintOpSettings::setModelName(const QString & modelName) { d->modelName = modelName; } KisPaintOpConfigWidget* KisPaintOpSettings::optionsWidget() const { if (d->settingsWidget.isNull()) return 0; return d->settingsWidget.data(); } bool KisPaintOpSettings::isValid() const { return true; } bool KisPaintOpSettings::isLoadable() { return isValid(); } QString KisPaintOpSettings::indirectPaintingCompositeOp() const { return COMPOSITE_ALPHA_DARKEN; } bool KisPaintOpSettings::isAirbrushing() const { return getBool(AIRBRUSH_ENABLED, false); } qreal KisPaintOpSettings::airbrushInterval() const { qreal rate = getDouble(AIRBRUSH_RATE, 1.0); if (rate == 0.0) { return LONG_TIME; } else { return 1000.0 / rate; } } bool KisPaintOpSettings::useSpacingUpdates() const { return getBool(SPACING_USE_UPDATES, false); } bool KisPaintOpSettings::needsAsynchronousUpdates() const { return false; } QPainterPath KisPaintOpSettings::brushOutline(const KisPaintInformation &info, const OutlineMode &mode) { QPainterPath path; if (mode.isVisible) { path = ellipseOutline(10, 10, 1.0, 0); if (mode.showTiltDecoration) { path.addPath(makeTiltIndicator(info, QPointF(0.0, 0.0), 0.0, 2.0)); } path.translate(info.pos()); } return path; } QPainterPath KisPaintOpSettings::ellipseOutline(qreal width, qreal height, qreal scale, qreal rotation) { QPainterPath path; QRectF ellipse(0, 0, width * scale, height * scale); ellipse.translate(-ellipse.center()); path.addEllipse(ellipse); QTransform m; m.reset(); m.rotate(rotation); path = m.map(path); return path; } QPainterPath KisPaintOpSettings::makeTiltIndicator(KisPaintInformation const& info, QPointF const& start, qreal maxLength, qreal angle) { if (maxLength == 0.0) maxLength = 50.0; maxLength = qMax(maxLength, 50.0); qreal const length = maxLength * (1 - info.tiltElevation(info, 60.0, 60.0, true)); qreal const baseAngle = 360.0 - fmod(KisPaintInformation::tiltDirection(info, true) * 360.0 + 270.0, 360.0); QLineF guideLine = QLineF::fromPolar(length, baseAngle + angle); guideLine.translate(start); QPainterPath ret; ret.moveTo(guideLine.p1()); ret.lineTo(guideLine.p2()); guideLine.setAngle(baseAngle - angle); ret.lineTo(guideLine.p2()); ret.lineTo(guideLine.p1()); return ret; } void KisPaintOpSettings::setCanvasRotation(qreal angle) { Private::DirtyNotificationsLocker locker(d.data()); setProperty("runtimeCanvasRotation", angle); setPropertyNotSaved("runtimeCanvasRotation"); } void KisPaintOpSettings::setCanvasMirroring(bool xAxisMirrored, bool yAxisMirrored) { Private::DirtyNotificationsLocker locker(d.data()); setProperty("runtimeCanvasMirroredX", xAxisMirrored); setPropertyNotSaved("runtimeCanvasMirroredX"); setProperty("runtimeCanvasMirroredY", yAxisMirrored); setPropertyNotSaved("runtimeCanvasMirroredY"); } void KisPaintOpSettings::setProperty(const QString & name, const QVariant & value) { if (value != KisPropertiesConfiguration::getProperty(name) && !d->disableDirtyNotifications) { KisPaintOpPresetSP presetSP = preset().toStrongRef(); if (presetSP) { presetSP->setPresetDirty(true); } } KisPropertiesConfiguration::setProperty(name, value); onPropertyChanged(); } void KisPaintOpSettings::onPropertyChanged() { KisPaintopSettingsUpdateProxy *proxy = d->updateProxyNoCreate(); if (proxy) { proxy->notifySettingsChanged(); } } bool KisPaintOpSettings::isLodUserAllowed(const KisPropertiesConfigurationSP config) { return config->getBool("lodUserAllowed", true); } void KisPaintOpSettings::setLodUserAllowed(KisPropertiesConfigurationSP config, bool value) { config->setProperty("lodUserAllowed", value); } bool KisPaintOpSettings::lodSizeThresholdSupported() const { return true; } qreal KisPaintOpSettings::lodSizeThreshold() const { return getDouble("lodSizeThreshold", 100.0); } void KisPaintOpSettings::setLodSizeThreshold(qreal value) { setProperty("lodSizeThreshold", value); } #include "kis_standard_uniform_properties_factory.h" QList KisPaintOpSettings::uniformProperties(KisPaintOpSettingsSP settings) { QList props = listWeakToStrong(d->uniformProperties); if (props.isEmpty()) { using namespace KisStandardUniformPropertiesFactory; props.append(createProperty(opacity, settings, d->updateProxyCreate())); props.append(createProperty(size, settings, d->updateProxyCreate())); props.append(createProperty(flow, settings, d->updateProxyCreate())); d->uniformProperties = listStrongToWeak(props); } return props; } diff --git a/libs/image/kis_fill_painter.cc b/libs/image/kis_fill_painter.cc index b38058d5cf..ba8c1db769 100644 --- a/libs/image/kis_fill_painter.cc +++ b/libs/image/kis_fill_painter.cc @@ -1,324 +1,324 @@ /* * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 Bart Coppens * Copyright (c) 2010 Lukáš Tvrdý * * 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_fill_painter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "generator/kis_generator.h" #include "filter/kis_filter_configuration.h" #include "generator/kis_generator_registry.h" #include "kis_processing_information.h" #include "kis_debug.h" #include "kis_image.h" #include "kis_layer.h" #include "kis_paint_device.h" #include #include "KoColorSpace.h" #include "kis_transaction.h" #include "kis_pixel_selection.h" #include #include #include "kis_selection_filters.h" KisFillPainter::KisFillPainter() : KisPainter() { initFillPainter(); } KisFillPainter::KisFillPainter(KisPaintDeviceSP device) : KisPainter(device) { initFillPainter(); } KisFillPainter::KisFillPainter(KisPaintDeviceSP device, KisSelectionSP selection) : KisPainter(device, selection) { initFillPainter(); } void KisFillPainter::initFillPainter() { m_width = m_height = -1; m_careForSelection = false; m_sizemod = 0; m_feather = 0; m_useCompositioning = false; m_threshold = 0; } void KisFillPainter::fillSelection(const QRect &rc, const KoColor &color) { KisPaintDeviceSP fillDevice = new KisPaintDevice(device()->colorSpace()); fillDevice->setDefaultPixel(color); bitBlt(rc.topLeft(), fillDevice, rc); } // 'regular' filling // XXX: This also needs renaming, since filling ought to keep the opacity and the composite op in mind, // this is more eraseToColor. void KisFillPainter::fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KoColor& kc, quint8 opacity) { if (w > 0 && h > 0) { // Make sure we're in the right colorspace KoColor kc2(kc); // get rid of const kc2.convertTo(device()->colorSpace()); quint8 * data = kc2.data(); device()->colorSpace()->setOpacity(data, opacity, 1); device()->fill(x1, y1, w, h, data); addDirtyRect(QRect(x1, y1, w, h)); } } -void KisFillPainter::fillRect(const QRect &rc, const KoPattern *pattern, const QPoint &offset) +void KisFillPainter::fillRect(const QRect &rc, const KoPatternSP pattern, const QPoint &offset) { fillRect(rc.x(), rc.y(), rc.width(), rc.height(), pattern, offset); } -void KisFillPainter::fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KoPattern * pattern, const QPoint &offset) +void KisFillPainter::fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KoPatternSP pattern, const QPoint &offset) { if (!pattern) return; if (!pattern->valid()) return; if (!device()) return; if (w < 1) return; if (h < 1) return; KisPaintDeviceSP patternLayer = new KisPaintDevice(device()->compositionSourceColorSpace(), pattern->name()); patternLayer->convertFromQImage(pattern->pattern(), 0); if (!offset.isNull()) { patternLayer->moveTo(offset); } fillRect(x1, y1, w, h, patternLayer, QRect(offset.x(), offset.y(), pattern->width(), pattern->height())); } void KisFillPainter::fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KisPaintDeviceSP device, const QRect& deviceRect) { const QRect &patternRect = deviceRect; const QRect fillRect(x1, y1, w, h); auto toPatternLocal = [](int value, int offset, int width) { const int normalizedValue = value - offset; return offset + (normalizedValue >= 0 ? normalizedValue % width : width - (-normalizedValue - 1) % width - 1); }; int dstY = fillRect.y(); while (dstY <= fillRect.bottom()) { const int dstRowsRemaining = fillRect.bottom() - dstY + 1; const int srcY = toPatternLocal(dstY, patternRect.y(), patternRect.height()); const int height = qMin(patternRect.height() - srcY + patternRect.y(), dstRowsRemaining); int dstX = fillRect.x(); while (dstX <= fillRect.right()) { const int dstColumnsRemaining = fillRect.right() - dstX + 1; const int srcX = toPatternLocal(dstX, patternRect.x(), patternRect.width()); const int width = qMin(patternRect.width() - srcX + patternRect.x(), dstColumnsRemaining); bitBlt(dstX, dstY, device, srcX, srcY, width, height); dstX += width; } dstY += height; } addDirtyRect(QRect(x1, y1, w, h)); } void KisFillPainter::fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KisFilterConfigurationSP generator) { if (!generator) return; KisGeneratorSP g = KisGeneratorRegistry::instance()->value(generator->name()); if (!device()) return; if (w < 1) return; if (h < 1) return; QRect tmpRc(x1, y1, w, h); KisProcessingInformation dstCfg(device(), tmpRc.topLeft(), 0); g->generate(dstCfg, tmpRc.size(), generator); addDirtyRect(tmpRc); } // flood filling void KisFillPainter::fillColor(int startX, int startY, KisPaintDeviceSP sourceDevice) { if (!m_useCompositioning) { if (m_sizemod || m_feather || compositeOp()->id() != COMPOSITE_OVER || opacity() != MAX_SELECTED || sourceDevice != device()) { warnKrita << "WARNING: Fast Flood Fill (no compositioning mode)" << "does not support compositeOps, opacity, " << "selection enhancements and separate source " << "devices"; } QRect fillBoundsRect(0, 0, m_width, m_height); QPoint startPoint(startX, startY); if (!fillBoundsRect.contains(startPoint)) return; KisScanlineFill gc(device(), startPoint, fillBoundsRect); gc.setThreshold(m_threshold); gc.fillColor(paintColor()); } else { genericFillStart(startX, startY, sourceDevice); // Now create a layer and fill it KisPaintDeviceSP filled = device()->createCompositionSourceDevice(); Q_CHECK_PTR(filled); KisFillPainter painter(filled); painter.fillRect(0, 0, m_width, m_height, paintColor()); painter.end(); genericFillEnd(filled); } } void KisFillPainter::fillPattern(int startX, int startY, KisPaintDeviceSP sourceDevice) { genericFillStart(startX, startY, sourceDevice); // Now create a layer and fill it KisPaintDeviceSP filled = device()->createCompositionSourceDevice(); Q_CHECK_PTR(filled); KisFillPainter painter(filled); painter.fillRect(0, 0, m_width, m_height, pattern()); painter.end(); genericFillEnd(filled); } void KisFillPainter::genericFillStart(int startX, int startY, KisPaintDeviceSP sourceDevice) { Q_ASSERT(m_width > 0); Q_ASSERT(m_height > 0); // Create a selection from the surrounding area m_fillSelection = createFloodSelection(startX, startY, sourceDevice); } void KisFillPainter::genericFillEnd(KisPaintDeviceSP filled) { if (progressUpdater() && progressUpdater()->interrupted()) { m_width = m_height = -1; return; } // TODO: filling using the correct bound of the selection would be better, *but* // the selection is limited to the exact bound of a layer, while in reality, we don't // want that, since we want a transparent layer to be completely filled // QRect rc = m_fillSelection->selectedExactRect(); /** * Apply the real selection to a filled one */ KisSelectionSP realSelection = selection(); if (realSelection) { m_fillSelection->pixelSelection()->applySelection( realSelection->projection(), SELECTION_INTERSECT); } setSelection(m_fillSelection); bitBlt(0, 0, filled, 0, 0, m_width, m_height); setSelection(realSelection); if (progressUpdater()) progressUpdater()->setProgress(100); m_width = m_height = -1; } KisSelectionSP KisFillPainter::createFloodSelection(int startX, int startY, KisPaintDeviceSP sourceDevice) { if (m_width < 0 || m_height < 0) { if (selection() && m_careForSelection) { QRect rc = selection()->selectedExactRect(); m_width = rc.width() - (startX - rc.x()); m_height = rc.height() - (startY - rc.y()); } } dbgImage << "Width: " << m_width << " Height: " << m_height; // Otherwise the width and height should have been set Q_ASSERT(m_width > 0 && m_height > 0); QRect fillBoundsRect(0, 0, m_width, m_height); QPoint startPoint(startX, startY); KisSelectionSP selection = new KisSelection(new KisSelectionDefaultBounds(device())); KisPixelSelectionSP pixelSelection = selection->pixelSelection(); if (!fillBoundsRect.contains(startPoint)) { return selection; } KisScanlineFill gc(sourceDevice, startPoint, fillBoundsRect); gc.setThreshold(m_threshold); gc.fillSelection(pixelSelection); if (m_sizemod > 0) { KisGrowSelectionFilter biggy(m_sizemod, m_sizemod); biggy.process(pixelSelection, selection->selectedRect().adjusted(-m_sizemod, -m_sizemod, m_sizemod, m_sizemod)); } else if (m_sizemod < 0) { KisShrinkSelectionFilter tiny(-m_sizemod, -m_sizemod, false); tiny.process(pixelSelection, selection->selectedRect()); } if (m_feather > 0) { KisFeatherSelectionFilter feathery(m_feather); feathery.process(pixelSelection, selection->selectedRect().adjusted(-m_feather, -m_feather, m_feather, m_feather)); } return selection; } diff --git a/libs/image/kis_fill_painter.h b/libs/image/kis_fill_painter.h index 4f1648a60e..404f070b84 100644 --- a/libs/image/kis_fill_painter.h +++ b/libs/image/kis_fill_painter.h @@ -1,281 +1,282 @@ /* * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 Bart Coppens * * 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_FILL_PAINTER_H_ #define KIS_FILL_PAINTER_H_ #include -#include "KoColor.h" -#include "KoColorSpaceRegistry.h" +#include +#include +#include #include "kis_painter.h" #include "kis_types.h" #include "kis_selection.h" #include -class KoPattern; + class KisFilterConfiguration; // XXX: Filling should set dirty rect. /** * This painter can be used to fill paint devices in different ways. This can also be used * for flood filling related operations. */ class KRITAIMAGE_EXPORT KisFillPainter : public KisPainter { public: /** * Construct an empty painter. Use the begin(KisPaintDeviceSP) method to attach * to a paint device */ KisFillPainter(); /** * Start painting on the specified paint device */ KisFillPainter(KisPaintDeviceSP device); KisFillPainter(KisPaintDeviceSP device, KisSelectionSP selection); private: void initFillPainter(); public: /** * Fill a rectangle with black transparent pixels (0, 0, 0, 0 for RGBA). */ void eraseRect(qint32 x1, qint32 y1, qint32 w, qint32 h); /** * Overloaded version of the above function. */ void eraseRect(const QRect& rc); /** * Fill current selection of KisPainter with a specified \p color. * * The filling rect is limited by \p rc to allow multithreaded * filling/processing. */ void fillSelection(const QRect &rc, const KoColor &color); /** * Fill a rectangle with a certain color. */ void fillRect(qint32 x, qint32 y, qint32 w, qint32 h, const KoColor& c); /** * Overloaded version of the above function. */ void fillRect(const QRect& rc, const KoColor& c); /** * Fill a rectangle with a certain color and opacity. */ void fillRect(qint32 x, qint32 y, qint32 w, qint32 h, const KoColor& c, quint8 opacity); /** * Overloaded version of the above function. */ void fillRect(const QRect& rc, const KoColor& c, quint8 opacity); /** * Fill a rectangle with a certain pattern. The pattern is repeated if it does not fit the * entire rectangle. */ - void fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KoPattern * pattern, const QPoint &offset = QPoint()); + void fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KoPatternSP pattern, const QPoint &offset = QPoint()); /** * Fill a rectangle with a certain pattern. The pattern is repeated if it does not fit the * entire rectangle. */ void fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KisPaintDeviceSP device, const QRect& deviceRect); /** * Overloaded version of the above function. */ - void fillRect(const QRect& rc, const KoPattern * pattern, const QPoint &offset = QPoint()); + void fillRect(const QRect& rc, const KoPatternSP pattern, const QPoint &offset = QPoint()); /** * Fill the specified area with the output of the generator plugin that is configured * in the generator parameter */ void fillRect(qint32 x1, qint32 y1, qint32 w, qint32 h, const KisFilterConfigurationSP generator); /** * Fills the enclosed area around the point with the set color. If * there is a selection, the whole selection is filled. Note that * you must have set the width and height on the painter if you * don't have a selection. * * @param startX the X position where the floodfill starts * @param startY the Y position where the floodfill starts * @param sourceDevice the sourceDevice that determines the area that * is floodfilled if sampleMerged is on */ void fillColor(int startX, int startY, KisPaintDeviceSP sourceDevice); /** * Fills the enclosed area around the point with the set pattern. * If there is a selection, the whole selection is filled. Note * that you must have set the width and height on the painter if * you don't have a selection. * * @param startX the X position where the floodfill starts * @param startY the Y position where the floodfill starts * @param sourceDevice the sourceDevice that determines the area that * is floodfilled if sampleMerged is on */ void fillPattern(int startX, int startY, KisPaintDeviceSP sourceDevice); /** * Returns a selection mask for the floodfill starting at the specified position. * * @param startX the X position where the floodfill starts * @param startY the Y position where the floodfill starts * @param sourceDevice the sourceDevice that determines the area that * is floodfilled if sampleMerged is on */ KisSelectionSP createFloodSelection(int startX, int startY, KisPaintDeviceSP sourceDevice); /** * Set the threshold for floodfill. The range is 0-255: 0 means the fill will only * fill parts that are the exact same color, 255 means anything will be filled */ void setFillThreshold(int threshold); /** Returns the fill threshold, see setFillThreshold for details */ int fillThreshold() const { return m_threshold; } bool useCompositioning() const { return m_useCompositioning; } void setUseCompositioning(bool useCompositioning) { m_useCompositioning = useCompositioning; } /** Sets the width of the paint device */ void setWidth(int w) { m_width = w; } /** Sets the height of the paint device */ void setHeight(int h) { m_height = h; } /** If true, floodfill doesn't fill outside the selected area of a layer */ bool careForSelection() const { return m_careForSelection; } /** Set caring for selection. See careForSelection for details */ void setCareForSelection(bool set) { m_careForSelection = set; } /** Sets the auto growth/shrinking radius */ void setSizemod(int sizemod) { m_sizemod = sizemod; } /** Sets how much to auto-grow or shrink (if @param sizemod is negative) the selection flood before painting, this affects every fill operation except fillRect */ int sizemod() { return m_sizemod; } /** Sets feathering radius */ void setFeather(int feather) { m_feather = feather; } /** defines the feathering radius for selection flood operations, this affects every fill operation except fillRect */ uint feather() { return m_feather; } private: // for floodfill void genericFillStart(int startX, int startY, KisPaintDeviceSP sourceDevice); void genericFillEnd(KisPaintDeviceSP filled); KisSelectionSP m_fillSelection; int m_feather; int m_sizemod; int m_threshold; int m_width, m_height; QRect m_rect; bool m_careForSelection; bool m_useCompositioning; }; inline void KisFillPainter::fillRect(qint32 x, qint32 y, qint32 w, qint32 h, const KoColor& c) { fillRect(x, y, w, h, c, OPACITY_OPAQUE_U8); } inline void KisFillPainter::fillRect(const QRect& rc, const KoColor& c) { fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, OPACITY_OPAQUE_U8); } inline void KisFillPainter::eraseRect(qint32 x1, qint32 y1, qint32 w, qint32 h) { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KoColor c(Qt::black, cs); fillRect(x1, y1, w, h, c, OPACITY_TRANSPARENT_U8); } inline void KisFillPainter::eraseRect(const QRect& rc) { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KoColor c(Qt::black, cs); fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, OPACITY_TRANSPARENT_U8); } inline void KisFillPainter::fillRect(const QRect& rc, const KoColor& c, quint8 opacity) { fillRect(rc.x(), rc.y(), rc.width(), rc.height(), c, opacity); } inline void KisFillPainter::setFillThreshold(int threshold) { m_threshold = threshold; } #endif //KIS_FILL_PAINTER_H_ diff --git a/libs/image/kis_gradient_painter.cc b/libs/image/kis_gradient_painter.cc index 4d472e4d7d..a945127ad1 100644 --- a/libs/image/kis_gradient_painter.cc +++ b/libs/image/kis_gradient_painter.cc @@ -1,731 +1,729 @@ /* * Copyright (c) 2004 Adrian Page * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_gradient_painter.h" #include #include #include #include #include "kis_global.h" #include "kis_paint_device.h" #include #include "kis_selection.h" #include #include "kis_image.h" #include "kis_random_accessor_ng.h" #include "kis_gradient_shape_strategy.h" #include "kis_polygonal_gradient_shape_strategy.h" #include "kis_cached_gradient_shape_strategy.h" #include "krita_utils.h" class CachedGradient : public KoAbstractGradient { public: - explicit CachedGradient(const KoAbstractGradient *gradient, qint32 steps, const KoColorSpace *cs) + explicit CachedGradient(const KoAbstractGradientSP gradient, qint32 steps, const KoColorSpace *cs) : KoAbstractGradient(gradient->filename()) + , m_subject(gradient) + , m_max(steps - 1) + , m_colorSpace(cs) + , m_black(KoColor(cs)) { - m_subject = gradient; - m_max = steps - 1; - m_colorSpace = cs; - - m_black = KoColor(cs); - KoColor tmpColor(m_colorSpace); for(qint32 i = 0; i < steps; i++) { m_subject->colorAt(tmpColor, qreal(i) / m_max); m_colors << tmpColor; } } ~CachedGradient() override {} - KoAbstractGradient* clone() const override { - return new CachedGradient(m_subject, m_max + 1, m_colorSpace); + KoAbstractGradientSP clone() const override { + return KoAbstractGradientSP(new CachedGradient(m_subject, m_max + 1, m_colorSpace)); } /** * Creates a QGradient from the gradient. * The resulting QGradient might differ from original gradient */ QGradient* toQGradient() const override { return m_subject->toQGradient(); } /// gets the color data at position 0 <= t <= 1 const quint8 *cachedAt(qreal t) const { qint32 tInt = t * m_max + 0.5; if (m_colors.size() > tInt) { return m_colors[tInt].data(); } else { return m_black.data(); } } void setColorSpace(KoColorSpace* colorSpace) { m_colorSpace = colorSpace; } const KoColorSpace * colorSpace() const { return m_colorSpace; } QByteArray generateMD5() const override { return QByteArray(); } private: - const KoAbstractGradient *m_subject; - const KoColorSpace *m_colorSpace; + const KoAbstractGradientSP m_subject; qint32 m_max; + const KoColorSpace *m_colorSpace; QVector m_colors; KoColor m_black; }; namespace { class LinearGradientStrategy : public KisGradientShapeStrategy { public: LinearGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd); double valueAt(double x, double y) const override; protected: double m_normalisedVectorX; double m_normalisedVectorY; double m_vectorLength; }; LinearGradientStrategy::LinearGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd) : KisGradientShapeStrategy(gradientVectorStart, gradientVectorEnd) { double dx = gradientVectorEnd.x() - gradientVectorStart.x(); double dy = gradientVectorEnd.y() - gradientVectorStart.y(); m_vectorLength = sqrt((dx * dx) + (dy * dy)); if (m_vectorLength < DBL_EPSILON) { m_normalisedVectorX = 0; m_normalisedVectorY = 0; } else { m_normalisedVectorX = dx / m_vectorLength; m_normalisedVectorY = dy / m_vectorLength; } } double LinearGradientStrategy::valueAt(double x, double y) const { double vx = x - m_gradientVectorStart.x(); double vy = y - m_gradientVectorStart.y(); // Project the vector onto the normalised gradient vector. double t = vx * m_normalisedVectorX + vy * m_normalisedVectorY; if (m_vectorLength < DBL_EPSILON) { t = 0; } else { // Scale to 0 to 1 over the gradient vector length. t /= m_vectorLength; } return t; } class BiLinearGradientStrategy : public LinearGradientStrategy { public: BiLinearGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd); double valueAt(double x, double y) const override; }; BiLinearGradientStrategy::BiLinearGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd) : LinearGradientStrategy(gradientVectorStart, gradientVectorEnd) { } double BiLinearGradientStrategy::valueAt(double x, double y) const { double t = LinearGradientStrategy::valueAt(x, y); // Reflect if (t < -DBL_EPSILON) { t = -t; } return t; } class RadialGradientStrategy : public KisGradientShapeStrategy { public: RadialGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd); double valueAt(double x, double y) const override; protected: double m_radius; }; RadialGradientStrategy::RadialGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd) : KisGradientShapeStrategy(gradientVectorStart, gradientVectorEnd) { double dx = gradientVectorEnd.x() - gradientVectorStart.x(); double dy = gradientVectorEnd.y() - gradientVectorStart.y(); m_radius = sqrt((dx * dx) + (dy * dy)); } double RadialGradientStrategy::valueAt(double x, double y) const { double dx = x - m_gradientVectorStart.x(); double dy = y - m_gradientVectorStart.y(); double distance = sqrt((dx * dx) + (dy * dy)); double t; if (m_radius < DBL_EPSILON) { t = 0; } else { t = distance / m_radius; } return t; } class SquareGradientStrategy : public KisGradientShapeStrategy { public: SquareGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd); double valueAt(double x, double y) const override; protected: double m_normalisedVectorX; double m_normalisedVectorY; double m_vectorLength; }; SquareGradientStrategy::SquareGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd) : KisGradientShapeStrategy(gradientVectorStart, gradientVectorEnd) { double dx = gradientVectorEnd.x() - gradientVectorStart.x(); double dy = gradientVectorEnd.y() - gradientVectorStart.y(); m_vectorLength = sqrt((dx * dx) + (dy * dy)); if (m_vectorLength < DBL_EPSILON) { m_normalisedVectorX = 0; m_normalisedVectorY = 0; } else { m_normalisedVectorX = dx / m_vectorLength; m_normalisedVectorY = dy / m_vectorLength; } } double SquareGradientStrategy::valueAt(double x, double y) const { double px = x - m_gradientVectorStart.x(); double py = y - m_gradientVectorStart.y(); double distance1 = 0; double distance2 = 0; if (m_vectorLength > DBL_EPSILON) { // Point to line distance is: // distance = ((l0.y() - l1.y()) * p.x() + (l1.x() - l0.x()) * p.y() + l0.x() * l1.y() - l1.x() * l0.y()) / m_vectorLength; // // Here l0 = (0, 0) and |l1 - l0| = 1 distance1 = -m_normalisedVectorY * px + m_normalisedVectorX * py; distance1 = fabs(distance1); // Rotate point by 90 degrees and get the distance to the perpendicular distance2 = -m_normalisedVectorY * -py + m_normalisedVectorX * px; distance2 = fabs(distance2); } double t = qMax(distance1, distance2) / m_vectorLength; return t; } class ConicalGradientStrategy : public KisGradientShapeStrategy { public: ConicalGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd); double valueAt(double x, double y) const override; protected: double m_vectorAngle; }; ConicalGradientStrategy::ConicalGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd) : KisGradientShapeStrategy(gradientVectorStart, gradientVectorEnd) { double dx = gradientVectorEnd.x() - gradientVectorStart.x(); double dy = gradientVectorEnd.y() - gradientVectorStart.y(); // Get angle from 0 to 2 PI. m_vectorAngle = atan2(dy, dx) + M_PI; } double ConicalGradientStrategy::valueAt(double x, double y) const { double px = x - m_gradientVectorStart.x(); double py = y - m_gradientVectorStart.y(); double angle = atan2(py, px) + M_PI; angle -= m_vectorAngle; if (angle < 0) { angle += 2 * M_PI; } double t = angle / (2 * M_PI); return t; } class ConicalSymetricGradientStrategy : public KisGradientShapeStrategy { public: ConicalSymetricGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd); double valueAt(double x, double y) const override; protected: double m_vectorAngle; }; ConicalSymetricGradientStrategy::ConicalSymetricGradientStrategy(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd) : KisGradientShapeStrategy(gradientVectorStart, gradientVectorEnd) { double dx = gradientVectorEnd.x() - gradientVectorStart.x(); double dy = gradientVectorEnd.y() - gradientVectorStart.y(); // Get angle from 0 to 2 PI. m_vectorAngle = atan2(dy, dx) + M_PI; } double ConicalSymetricGradientStrategy::valueAt(double x, double y) const { double px = x - m_gradientVectorStart.x(); double py = y - m_gradientVectorStart.y(); double angle = atan2(py, px) + M_PI; angle -= m_vectorAngle; if (angle < 0) { angle += 2 * M_PI; } double t; if (angle < M_PI) { t = angle / M_PI; } else { t = 1 - ((angle - M_PI) / M_PI); } return t; } class GradientRepeatStrategy { public: GradientRepeatStrategy() {} virtual ~GradientRepeatStrategy() {} virtual double valueAt(double t) const = 0; }; class GradientRepeatNoneStrategy : public GradientRepeatStrategy { public: static GradientRepeatNoneStrategy *instance(); double valueAt(double t) const override; private: GradientRepeatNoneStrategy() {} static GradientRepeatNoneStrategy *m_instance; }; GradientRepeatNoneStrategy *GradientRepeatNoneStrategy::m_instance = 0; GradientRepeatNoneStrategy *GradientRepeatNoneStrategy::instance() { if (m_instance == 0) { m_instance = new GradientRepeatNoneStrategy(); Q_CHECK_PTR(m_instance); } return m_instance; } // Output is clamped to 0 to 1. double GradientRepeatNoneStrategy::valueAt(double t) const { double value = t; if (t < DBL_EPSILON) { value = 0; } else if (t > 1 - DBL_EPSILON) { value = 1; } return value; } class GradientRepeatForwardsStrategy : public GradientRepeatStrategy { public: static GradientRepeatForwardsStrategy *instance(); double valueAt(double t) const override; private: GradientRepeatForwardsStrategy() {} static GradientRepeatForwardsStrategy *m_instance; }; GradientRepeatForwardsStrategy *GradientRepeatForwardsStrategy::m_instance = 0; GradientRepeatForwardsStrategy *GradientRepeatForwardsStrategy::instance() { if (m_instance == 0) { m_instance = new GradientRepeatForwardsStrategy(); Q_CHECK_PTR(m_instance); } return m_instance; } // Output is 0 to 1, 0 to 1, 0 to 1... double GradientRepeatForwardsStrategy::valueAt(double t) const { int i = static_cast(t); if (t < DBL_EPSILON) { i--; } double value = t - i; return value; } class GradientRepeatAlternateStrategy : public GradientRepeatStrategy { public: static GradientRepeatAlternateStrategy *instance(); double valueAt(double t) const override; private: GradientRepeatAlternateStrategy() {} static GradientRepeatAlternateStrategy *m_instance; }; GradientRepeatAlternateStrategy *GradientRepeatAlternateStrategy::m_instance = 0; GradientRepeatAlternateStrategy *GradientRepeatAlternateStrategy::instance() { if (m_instance == 0) { m_instance = new GradientRepeatAlternateStrategy(); Q_CHECK_PTR(m_instance); } return m_instance; } // Output is 0 to 1, 1 to 0, 0 to 1, 1 to 0... double GradientRepeatAlternateStrategy::valueAt(double t) const { if (t < 0) { t = -t; } int i = static_cast(t); double value = t - i; if (i % 2 == 1) { value = 1 - value; } return value; } } struct Q_DECL_HIDDEN KisGradientPainter::Private { enumGradientShape shape; struct ProcessRegion { ProcessRegion() {} ProcessRegion(QSharedPointer _precalculatedShapeStrategy, const QRect &_processRect) : precalculatedShapeStrategy(_precalculatedShapeStrategy), processRect(_processRect) {} QSharedPointer precalculatedShapeStrategy; QRect processRect; }; QVector processRegions; }; KisGradientPainter::KisGradientPainter() : m_d(new Private()) { } KisGradientPainter::KisGradientPainter(KisPaintDeviceSP device) : KisPainter(device), m_d(new Private()) { } KisGradientPainter::KisGradientPainter(KisPaintDeviceSP device, KisSelectionSP selection) : KisPainter(device, selection), m_d(new Private()) { } KisGradientPainter::~KisGradientPainter() { } void KisGradientPainter::setGradientShape(enumGradientShape shape) { m_d->shape = shape; } KisGradientShapeStrategy* createPolygonShapeStrategy(const QPainterPath &path, const QRect &boundingRect) { // TODO: implement UI for exponent option const qreal exponent = 2.0; KisGradientShapeStrategy *strategy = new KisPolygonalGradientShapeStrategy(path, exponent); KIS_ASSERT_RECOVER_NOOP(boundingRect.width() >= 3 && boundingRect.height() >= 3); const qreal step = qMin(qreal(8.0), KritaUtils::maxDimensionPortion(boundingRect, 0.01, 2)); return new KisCachedGradientShapeStrategy(boundingRect, step, step, strategy); } /** * TODO: make this call happen asynchronously when the user does nothing */ void KisGradientPainter::precalculateShape() { if (!m_d->processRegions.isEmpty()) return; QPainterPath path; if (selection()) { if (!selection()->outlineCacheValid()) { selection()->recalculateOutlineCache(); } KIS_ASSERT_RECOVER_RETURN(selection()->outlineCacheValid()); KIS_ASSERT_RECOVER_RETURN(!selection()->outlineCache().isEmpty()); path = selection()->outlineCache(); } else { path.addRect(device()->defaultBounds()->bounds()); } QList splitPaths = KritaUtils::splitDisjointPaths(path); Q_FOREACH (const QPainterPath &subpath, splitPaths) { QRect boundingRect = subpath.boundingRect().toAlignedRect(); if (boundingRect.width() < 3 || boundingRect.height() < 3) { boundingRect = kisGrowRect(boundingRect, 2); } Private::ProcessRegion r(toQShared(createPolygonShapeStrategy(subpath, boundingRect)), boundingRect); m_d->processRegions << r; } } bool KisGradientPainter::paintGradient(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd, enumGradientRepeat repeat, double antiAliasThreshold, bool reverseGradient, qint32 startx, qint32 starty, qint32 width, qint32 height) { return paintGradient(gradientVectorStart, gradientVectorEnd, repeat, antiAliasThreshold, reverseGradient, QRect(startx, starty, width, height)); } bool KisGradientPainter::paintGradient(const QPointF& gradientVectorStart, const QPointF& gradientVectorEnd, enumGradientRepeat repeat, double antiAliasThreshold, bool reverseGradient, const QRect &applyRect) { Q_UNUSED(antiAliasThreshold); if (!gradient()) return false; QRect requestedRect = applyRect; //If the device has a selection only iterate over that selection united with our area of interest if (selection()) { requestedRect &= selection()->selectedExactRect(); } QSharedPointer shapeStrategy; switch (m_d->shape) { case GradientShapeLinear: { Private::ProcessRegion r(toQShared(new LinearGradientStrategy(gradientVectorStart, gradientVectorEnd)), requestedRect); m_d->processRegions.clear(); m_d->processRegions << r; break; } case GradientShapeBiLinear: { Private::ProcessRegion r(toQShared(new BiLinearGradientStrategy(gradientVectorStart, gradientVectorEnd)), requestedRect); m_d->processRegions.clear(); m_d->processRegions << r; break; } case GradientShapeRadial: { Private::ProcessRegion r(toQShared(new RadialGradientStrategy(gradientVectorStart, gradientVectorEnd)), requestedRect); m_d->processRegions.clear(); m_d->processRegions << r; break; } case GradientShapeSquare: { Private::ProcessRegion r(toQShared(new SquareGradientStrategy(gradientVectorStart, gradientVectorEnd)), requestedRect); m_d->processRegions.clear(); m_d->processRegions << r; break; } case GradientShapeConical: { Private::ProcessRegion r(toQShared(new ConicalGradientStrategy(gradientVectorStart, gradientVectorEnd)), requestedRect); m_d->processRegions.clear(); m_d->processRegions << r; break; } case GradientShapeConicalSymetric: { Private::ProcessRegion r(toQShared(new ConicalSymetricGradientStrategy(gradientVectorStart, gradientVectorEnd)), requestedRect); m_d->processRegions.clear(); m_d->processRegions << r; break; } case GradientShapePolygonal: precalculateShape(); repeat = GradientRepeatNone; break; } GradientRepeatStrategy *repeatStrategy = 0; switch (repeat) { case GradientRepeatNone: repeatStrategy = GradientRepeatNoneStrategy::instance(); break; case GradientRepeatForwards: repeatStrategy = GradientRepeatForwardsStrategy::instance(); break; case GradientRepeatAlternate: repeatStrategy = GradientRepeatAlternateStrategy::instance(); break; } Q_ASSERT(repeatStrategy != 0); KisPaintDeviceSP dev = device()->createCompositionSourceDevice(); const KoColorSpace * colorSpace = dev->colorSpace(); const qint32 pixelSize = colorSpace->pixelSize(); Q_FOREACH (const Private::ProcessRegion &r, m_d->processRegions) { QRect processRect = r.processRect; QSharedPointer shapeStrategy = r.precalculatedShapeStrategy; CachedGradient cachedGradient(gradient(), qMax(processRect.width(), processRect.height()), colorSpace); KisSequentialIteratorProgress it(dev, processRect, progressUpdater()); while (it.nextPixel()) { double t = shapeStrategy->valueAt(it.x(), it.y()); t = repeatStrategy->valueAt(t); if (reverseGradient) { t = 1 - t; } memcpy(it.rawData(), cachedGradient.cachedAt(t), pixelSize); } bitBlt(processRect.topLeft(), dev, processRect); } return true; } diff --git a/libs/image/kis_painter.cc b/libs/image/kis_painter.cc index 7f8036058b..3289bfc065 100644 --- a/libs/image/kis_painter.cc +++ b/libs/image/kis_painter.cc @@ -1,2985 +1,2983 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 Cyrille Berger * Copyright (c) 2008-2010 Lukáš Tvrdý * Copyright (c) 2010 José Luis Vergara Toloza * Copyright (c) 2011 Silvio Heinrich * * 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_painter.h" #include #include #include #include #include #ifndef Q_OS_WIN #include #endif #include #include #include #include #include #include #include #include "kis_image.h" #include "filter/kis_filter.h" #include "kis_layer.h" #include "kis_paint_device.h" #include "kis_fixed_paint_device.h" #include "kis_transaction.h" #include "kis_vec.h" #include "kis_iterator_ng.h" #include "kis_random_accessor_ng.h" #include "filter/kis_filter_configuration.h" #include "kis_pixel_selection.h" #include #include "kis_paintop_registry.h" #include "kis_perspective_math.h" #include "tiles3/kis_random_accessor.h" #include #include #include "kis_lod_transform.h" #include "kis_algebra_2d.h" #include "krita_utils.h" // Maximum distance from a Bezier control point to the line through the start // and end points for the curve to be considered flat. #define BEZIER_FLATNESS_THRESHOLD 0.5 #include "kis_painter_p.h" KisPainter::KisPainter() : d(new Private(this)) { init(); } KisPainter::KisPainter(KisPaintDeviceSP device) : d(new Private(this, device->colorSpace())) { init(); Q_ASSERT(device); begin(device); } KisPainter::KisPainter(KisPaintDeviceSP device, KisSelectionSP selection) : d(new Private(this, device->colorSpace())) { init(); Q_ASSERT(device); begin(device); d->selection = selection; } void KisPainter::init() { d->selection = 0 ; d->transaction = 0; d->paintOp = 0; - d->pattern = 0; d->sourceLayer = 0; d->fillStyle = FillStyleNone; d->strokeStyle = StrokeStyleBrush; d->antiAliasPolygonFill = true; d->progressUpdater = 0; - d->gradient = 0; d->maskPainter = 0; d->fillPainter = 0; d->maskImageWidth = 255; d->maskImageHeight = 255; d->mirrorHorizontally = false; d->mirrorVertically = false; d->isOpacityUnit = true; d->paramInfo = KoCompositeOp::ParameterInfo(); d->renderingIntent = KoColorConversionTransformation::internalRenderingIntent(); d->conversionFlags = KoColorConversionTransformation::internalConversionFlags(); } KisPainter::~KisPainter() { // TODO: Maybe, don't be that strict? // deleteTransaction(); end(); delete d->paintOp; delete d->maskPainter; delete d->fillPainter; delete d; } template void copyAreaOptimizedImpl(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &srcRect) { const QRect dstRect(dstPt, srcRect.size()); const QRect srcExtent = src->extent(); const QRect dstExtent = dst->extent(); const QRect srcSampleRect = srcExtent & srcRect; const QRect dstSampleRect = dstExtent & dstRect; const bool srcEmpty = srcSampleRect.isEmpty(); const bool dstEmpty = dstSampleRect.isEmpty(); if (!srcEmpty || !dstEmpty) { if (srcEmpty) { dst->clear(dstRect); } else { QRect srcCopyRect = srcRect; QRect dstCopyRect = dstRect; if (!srcExtent.contains(srcRect)) { if (src->defaultPixel() == dst->defaultPixel()) { const QRect dstSampleInSrcCoords = dstSampleRect.translated(srcRect.topLeft() - dstPt); if (dstSampleInSrcCoords.isEmpty() || srcSampleRect.contains(dstSampleInSrcCoords)) { srcCopyRect = srcSampleRect; } else { srcCopyRect = srcSampleRect | dstSampleInSrcCoords; } dstCopyRect = QRect(dstPt + srcCopyRect.topLeft() - srcRect.topLeft(), srcCopyRect.size()); } } KisPainter gc(dst); gc.setCompositeOp(dst->colorSpace()->compositeOp(COMPOSITE_COPY)); if (useOldData) { gc.bitBltOldData(dstCopyRect.topLeft(), src, srcCopyRect); } else { gc.bitBlt(dstCopyRect.topLeft(), src, srcCopyRect); } } } } void KisPainter::copyAreaOptimized(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &srcRect) { copyAreaOptimizedImpl(dstPt, src, dst, srcRect); } void KisPainter::copyAreaOptimizedOldData(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &srcRect) { copyAreaOptimizedImpl(dstPt, src, dst, srcRect); } void KisPainter::copyAreaOptimized(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &originalSrcRect, KisSelectionSP selection) { if (!selection) { copyAreaOptimized(dstPt, src, dst, originalSrcRect); return; } const QRect selectionRect = selection->selectedRect(); const QRect srcRect = originalSrcRect & selectionRect; const QPoint dstOffset = srcRect.topLeft() - originalSrcRect.topLeft(); const QRect dstRect = QRect(dstPt + dstOffset, srcRect.size()); const bool srcEmpty = (src->extent() & srcRect).isEmpty(); const bool dstEmpty = (dst->extent() & dstRect).isEmpty(); if (!srcEmpty || !dstEmpty) { //if (srcEmpty) { // doesn't support dstRect // dst->clearSelection(selection); // } else */ { KisPainter gc(dst); gc.setSelection(selection); gc.setCompositeOp(dst->colorSpace()->compositeOp(COMPOSITE_COPY)); gc.bitBlt(dstRect.topLeft(), src, srcRect); } } } KisPaintDeviceSP KisPainter::convertToAlphaAsAlpha(KisPaintDeviceSP src) { const KoColorSpace *srcCS = src->colorSpace(); const QRect processRect = src->extent(); KisPaintDeviceSP dst(new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8())); if (processRect.isEmpty()) return dst; KisSequentialConstIterator srcIt(src, processRect); KisSequentialIterator dstIt(dst, processRect); while (srcIt.nextPixel() && dstIt.nextPixel()) { const quint8 *srcPtr = srcIt.rawDataConst(); quint8 *alpha8Ptr = dstIt.rawData(); const quint8 white = srcCS->intensity8(srcPtr); const quint8 alpha = srcCS->opacityU8(srcPtr); *alpha8Ptr = KoColorSpaceMaths::multiply(alpha, KoColorSpaceMathsTraits::unitValue - white); } return dst; } KisPaintDeviceSP KisPainter::convertToAlphaAsGray(KisPaintDeviceSP src) { const KoColorSpace *srcCS = src->colorSpace(); const QRect processRect = src->extent(); KisPaintDeviceSP dst(new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8())); if (processRect.isEmpty()) return dst; KisSequentialConstIterator srcIt(src, processRect); KisSequentialIterator dstIt(dst, processRect); while (srcIt.nextPixel() && dstIt.nextPixel()) { const quint8 *srcPtr = srcIt.rawDataConst(); quint8 *alpha8Ptr = dstIt.rawData(); *alpha8Ptr = srcCS->intensity8(srcPtr); } return dst; } bool KisPainter::checkDeviceHasTransparency(KisPaintDeviceSP dev) { const QRect deviceBounds = dev->exactBounds(); const QRect imageBounds = dev->defaultBounds()->bounds(); if (deviceBounds.isEmpty() || (deviceBounds & imageBounds) != imageBounds) { return true; } const KoColorSpace *cs = dev->colorSpace(); KisSequentialConstIterator it(dev, deviceBounds); while(it.nextPixel()) { if (cs->opacityU8(it.rawDataConst()) != OPACITY_OPAQUE_U8) { return true; } } return false; } void KisPainter::begin(KisPaintDeviceSP device) { begin(device, d->selection); } void KisPainter::begin(KisPaintDeviceSP device, KisSelectionSP selection) { if (!device) return; d->selection = selection; Q_ASSERT(device->colorSpace()); end(); d->device = device; d->colorSpace = device->colorSpace(); d->compositeOp = d->colorSpace->compositeOp(COMPOSITE_OVER); d->pixelSize = device->pixelSize(); } void KisPainter::end() { Q_ASSERT_X(!d->transaction, "KisPainter::end()", "end() was called for the painter having a transaction. " "Please use end/deleteTransaction() instead"); } void KisPainter::beginTransaction(const KUndo2MagicString& transactionName,int timedID) { Q_ASSERT_X(!d->transaction, "KisPainter::beginTransaction()", "You asked for a new transaction while still having " "another one. Please finish the first one with " "end/deleteTransaction() first"); d->transaction = new KisTransaction(transactionName, d->device); Q_CHECK_PTR(d->transaction); d->transaction->undoCommand()->setTimedID(timedID); } void KisPainter::revertTransaction() { Q_ASSERT_X(d->transaction, "KisPainter::revertTransaction()", "No transaction is in progress"); d->transaction->revert(); delete d->transaction; d->transaction = 0; } void KisPainter::endTransaction(KisUndoAdapter *undoAdapter) { Q_ASSERT_X(d->transaction, "KisPainter::endTransaction()", "No transaction is in progress"); d->transaction->commit(undoAdapter); delete d->transaction; d->transaction = 0; } void KisPainter::endTransaction(KisPostExecutionUndoAdapter *undoAdapter) { Q_ASSERT_X(d->transaction, "KisPainter::endTransaction()", "No transaction is in progress"); d->transaction->commit(undoAdapter); delete d->transaction; d->transaction = 0; } KUndo2Command* KisPainter::endAndTakeTransaction() { Q_ASSERT_X(d->transaction, "KisPainter::endTransaction()", "No transaction is in progress"); KUndo2Command *transactionData = d->transaction->endAndTake(); delete d->transaction; d->transaction = 0; return transactionData; } void KisPainter::deleteTransaction() { if (!d->transaction) return; delete d->transaction; d->transaction = 0; } void KisPainter::putTransaction(KisTransaction* transaction) { Q_ASSERT_X(!d->transaction, "KisPainter::putTransaction()", "You asked for a new transaction while still having " "another one. Please finish the first one with " "end/deleteTransaction() first"); d->transaction = transaction; } KisTransaction* KisPainter::takeTransaction() { Q_ASSERT_X(d->transaction, "KisPainter::takeTransaction()", "No transaction is in progress"); KisTransaction *temp = d->transaction; d->transaction = 0; return temp; } QVector KisPainter::takeDirtyRegion() { QVector vrect = d->dirtyRects; d->dirtyRects.clear(); return vrect; } void KisPainter::addDirtyRect(const QRect & rc) { QRect r = rc.normalized(); if (r.isValid()) { d->dirtyRects.append(rc); } } void KisPainter::addDirtyRects(const QVector &rects) { d->dirtyRects.reserve(d->dirtyRects.size() + rects.size()); Q_FOREACH (const QRect &rc, rects) { const QRect r = rc.normalized(); if (r.isValid()) { d->dirtyRects.append(rc); } } } inline bool KisPainter::Private::tryReduceSourceRect(const KisPaintDevice *srcDev, QRect *srcRect, qint32 *srcX, qint32 *srcY, qint32 *srcWidth, qint32 *srcHeight, qint32 *dstX, qint32 *dstY) { /** * In case of COMPOSITE_COPY and Wrap Around Mode even the pixels * outside the device extent matter, because they will be either * directly copied (former case) or cloned from another area of * the image. */ if (compositeOp->id() != COMPOSITE_COPY && compositeOp->id() != COMPOSITE_DESTINATION_IN && compositeOp->id() != COMPOSITE_DESTINATION_ATOP && !srcDev->defaultBounds()->wrapAroundMode()) { /** * If srcDev->extent() (the area of the tiles containing * srcDev) is smaller than srcRect, then shrink srcRect to * that size. This is done as a speed optimization, useful for * stack recomposition in KisImage. srcRect won't grow if * srcDev->extent() is larger. */ *srcRect &= srcDev->extent(); if (srcRect->isEmpty()) return true; // Readjust the function paramenters to the new dimensions. *dstX += srcRect->x() - *srcX; // This will only add, not subtract *dstY += srcRect->y() - *srcY; // Idem srcRect->getRect(srcX, srcY, srcWidth, srcHeight); } return false; } void KisPainter::bitBltWithFixedSelection(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, qint32 selX, qint32 selY, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight) { // TODO: get selX and selY working as intended /* This check for nonsense ought to be a Q_ASSERT. However, when paintops are just initializing they perform some dummy passes with those parameters, and it must not crash */ if (srcWidth == 0 || srcHeight == 0) return; if (srcDev.isNull()) return; if (d->device.isNull()) return; // Check that selection has an alpha colorspace, crash if false Q_ASSERT(selection->colorSpace() == KoColorSpaceRegistry::instance()->alpha8()); QRect srcRect = QRect(srcX, srcY, srcWidth, srcHeight); QRect selRect = QRect(selX, selY, srcWidth, srcHeight); /* Trying to read outside a KisFixedPaintDevice is inherently wrong and shouldn't be done, so crash if someone attempts to do this. Don't resize YET as it would obfuscate the mistake. */ Q_ASSERT(selection->bounds().contains(selRect)); Q_UNUSED(selRect); // only used by the above Q_ASSERT /** * An optimization, which crops the source rect by the bounds of * the source device when it is possible */ if (d->tryReduceSourceRect(srcDev, &srcRect, &srcX, &srcY, &srcWidth, &srcHeight, &dstX, &dstY)) return; /* Create an intermediate byte array to hold information before it is written to the current paint device (d->device) */ quint8* dstBytes = 0; try { dstBytes = new quint8[srcWidth * srcHeight * d->device->pixelSize()]; } catch (const std::bad_alloc&) { warnKrita << "KisPainter::bitBltWithFixedSelection std::bad_alloc for " << srcWidth << " * " << srcHeight << " * " << d->device->pixelSize() << "dst bytes"; return; } d->device->readBytes(dstBytes, dstX, dstY, srcWidth, srcHeight); // Copy the relevant bytes of raw data from srcDev quint8* srcBytes = 0; try { srcBytes = new quint8[srcWidth * srcHeight * srcDev->pixelSize()]; } catch (const std::bad_alloc&) { warnKrita << "KisPainter::bitBltWithFixedSelection std::bad_alloc for " << srcWidth << " * " << srcHeight << " * " << d->device->pixelSize() << "src bytes"; return; } srcDev->readBytes(srcBytes, srcX, srcY, srcWidth, srcHeight); QRect selBounds = selection->bounds(); const quint8 *selRowStart = selection->data() + (selBounds.width() * (selY - selBounds.top()) + (selX - selBounds.left())) * selection->pixelSize(); /* * This checks whether there is nothing selected. */ if (!d->selection) { /* As there's nothing selected, blit to dstBytes (intermediary bit array), ignoring d->selection (the user selection)*/ d->paramInfo.dstRowStart = dstBytes; d->paramInfo.dstRowStride = srcWidth * d->device->pixelSize(); d->paramInfo.srcRowStart = srcBytes; d->paramInfo.srcRowStride = srcWidth * srcDev->pixelSize(); d->paramInfo.maskRowStart = selRowStart; d->paramInfo.maskRowStride = selBounds.width() * selection->pixelSize(); d->paramInfo.rows = srcHeight; d->paramInfo.cols = srcWidth; d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); } else { /* Read the user selection (d->selection) bytes into an array, ready to merge in the next block*/ quint32 totalBytes = srcWidth * srcHeight * selection->pixelSize(); quint8* mergedSelectionBytes = 0; try { mergedSelectionBytes = new quint8[ totalBytes ]; } catch (const std::bad_alloc&) { warnKrita << "KisPainter::bitBltWithFixedSelection std::bad_alloc for " << srcWidth << " * " << srcHeight << " * " << d->device->pixelSize() << "total bytes"; return; } d->selection->projection()->readBytes(mergedSelectionBytes, dstX, dstY, srcWidth, srcHeight); // Merge selections here by multiplying them - compositeOP(COMPOSITE_MULT) d->paramInfo.dstRowStart = mergedSelectionBytes; d->paramInfo.dstRowStride = srcWidth * selection->pixelSize(); d->paramInfo.srcRowStart = selRowStart; d->paramInfo.srcRowStride = selBounds.width() * selection->pixelSize(); d->paramInfo.maskRowStart = 0; d->paramInfo.maskRowStride = 0; d->paramInfo.rows = srcHeight; d->paramInfo.cols = srcWidth; KoColorSpaceRegistry::instance()->alpha8()->compositeOp(COMPOSITE_MULT)->composite(d->paramInfo); // Blit to dstBytes (intermediary bit array) d->paramInfo.dstRowStart = dstBytes; d->paramInfo.dstRowStride = srcWidth * d->device->pixelSize(); d->paramInfo.srcRowStart = srcBytes; d->paramInfo.srcRowStride = srcWidth * srcDev->pixelSize(); d->paramInfo.maskRowStart = mergedSelectionBytes; d->paramInfo.maskRowStride = srcWidth * selection->pixelSize(); d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); delete[] mergedSelectionBytes; } d->device->writeBytes(dstBytes, dstX, dstY, srcWidth, srcHeight); delete[] dstBytes; delete[] srcBytes; addDirtyRect(QRect(dstX, dstY, srcWidth, srcHeight)); } void KisPainter::bitBltWithFixedSelection(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, qint32 srcWidth, qint32 srcHeight) { bitBltWithFixedSelection(dstX, dstY, srcDev, selection, 0, 0, 0, 0, srcWidth, srcHeight); } template void KisPainter::bitBltImpl(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight) { /* This check for nonsense ought to be a Q_ASSERT. However, when paintops are just initializing they perform some dummy passes with those parameters, and it must not crash */ if (srcWidth == 0 || srcHeight == 0) return; if (srcDev.isNull()) return; if (d->device.isNull()) return; QRect srcRect = QRect(srcX, srcY, srcWidth, srcHeight); if (d->compositeOp->id() == COMPOSITE_COPY) { if(!d->selection && d->isOpacityUnit && srcX == dstX && srcY == dstY && d->device->fastBitBltPossible(srcDev)) { if(useOldSrcData) { d->device->fastBitBltOldData(srcDev, srcRect); } else { d->device->fastBitBlt(srcDev, srcRect); } addDirtyRect(srcRect); return; } } else { /** * An optimization, which crops the source rect by the bounds of * the source device when it is possible */ if (d->tryReduceSourceRect(srcDev, &srcRect, &srcX, &srcY, &srcWidth, &srcHeight, &dstX, &dstY)) return; } qint32 dstY_ = dstY; qint32 srcY_ = srcY; qint32 rowsRemaining = srcHeight; // Read below KisRandomConstAccessorSP srcIt = srcDev->createRandomConstAccessorNG(srcX, srcY); KisRandomAccessorSP dstIt = d->device->createRandomAccessorNG(dstX, dstY); /* Here be a huge block of verbose code that does roughly the same than the other bit blit operations. This one is longer than the rest in an effort to optimize speed and memory use */ if (d->selection) { KisPaintDeviceSP selectionProjection(d->selection->projection()); KisRandomConstAccessorSP maskIt = selectionProjection->createRandomConstAccessorNG(dstX, dstY); while (rowsRemaining > 0) { qint32 dstX_ = dstX; qint32 srcX_ = srcX; qint32 columnsRemaining = srcWidth; qint32 numContiguousDstRows = dstIt->numContiguousRows(dstY_); qint32 numContiguousSrcRows = srcIt->numContiguousRows(srcY_); qint32 numContiguousSelRows = maskIt->numContiguousRows(dstY_); qint32 rows = qMin(numContiguousDstRows, numContiguousSrcRows); rows = qMin(rows, numContiguousSelRows); rows = qMin(rows, rowsRemaining); while (columnsRemaining > 0) { qint32 numContiguousDstColumns = dstIt->numContiguousColumns(dstX_); qint32 numContiguousSrcColumns = srcIt->numContiguousColumns(srcX_); qint32 numContiguousSelColumns = maskIt->numContiguousColumns(dstX_); qint32 columns = qMin(numContiguousDstColumns, numContiguousSrcColumns); columns = qMin(columns, numContiguousSelColumns); columns = qMin(columns, columnsRemaining); qint32 srcRowStride = srcIt->rowStride(srcX_, srcY_); srcIt->moveTo(srcX_, srcY_); qint32 dstRowStride = dstIt->rowStride(dstX_, dstY_); dstIt->moveTo(dstX_, dstY_); qint32 maskRowStride = maskIt->rowStride(dstX_, dstY_); maskIt->moveTo(dstX_, dstY_); d->paramInfo.dstRowStart = dstIt->rawData(); d->paramInfo.dstRowStride = dstRowStride; // if we don't use the oldRawData, we need to access the rawData of the source device. d->paramInfo.srcRowStart = useOldSrcData ? srcIt->oldRawData() : static_cast(srcIt.data())->rawData(); d->paramInfo.srcRowStride = srcRowStride; d->paramInfo.maskRowStart = static_cast(maskIt.data())->rawData(); d->paramInfo.maskRowStride = maskRowStride; d->paramInfo.rows = rows; d->paramInfo.cols = columns; d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); srcX_ += columns; dstX_ += columns; columnsRemaining -= columns; } srcY_ += rows; dstY_ += rows; rowsRemaining -= rows; } } else { while (rowsRemaining > 0) { qint32 dstX_ = dstX; qint32 srcX_ = srcX; qint32 columnsRemaining = srcWidth; qint32 numContiguousDstRows = dstIt->numContiguousRows(dstY_); qint32 numContiguousSrcRows = srcIt->numContiguousRows(srcY_); qint32 rows = qMin(numContiguousDstRows, numContiguousSrcRows); rows = qMin(rows, rowsRemaining); while (columnsRemaining > 0) { qint32 numContiguousDstColumns = dstIt->numContiguousColumns(dstX_); qint32 numContiguousSrcColumns = srcIt->numContiguousColumns(srcX_); qint32 columns = qMin(numContiguousDstColumns, numContiguousSrcColumns); columns = qMin(columns, columnsRemaining); qint32 srcRowStride = srcIt->rowStride(srcX_, srcY_); srcIt->moveTo(srcX_, srcY_); qint32 dstRowStride = dstIt->rowStride(dstX_, dstY_); dstIt->moveTo(dstX_, dstY_); d->paramInfo.dstRowStart = dstIt->rawData(); d->paramInfo.dstRowStride = dstRowStride; // if we don't use the oldRawData, we need to access the rawData of the source device. d->paramInfo.srcRowStart = useOldSrcData ? srcIt->oldRawData() : static_cast(srcIt.data())->rawData(); d->paramInfo.srcRowStride = srcRowStride; d->paramInfo.maskRowStart = 0; d->paramInfo.maskRowStride = 0; d->paramInfo.rows = rows; d->paramInfo.cols = columns; d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); srcX_ += columns; dstX_ += columns; columnsRemaining -= columns; } srcY_ += rows; dstY_ += rows; rowsRemaining -= rows; } } addDirtyRect(QRect(dstX, dstY, srcWidth, srcHeight)); } void KisPainter::bitBlt(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight) { bitBltImpl(dstX, dstY, srcDev, srcX, srcY, srcWidth, srcHeight); } void KisPainter::bitBlt(const QPoint & pos, const KisPaintDeviceSP srcDev, const QRect & srcRect) { bitBlt(pos.x(), pos.y(), srcDev, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height()); } void KisPainter::bitBltOldData(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight) { bitBltImpl(dstX, dstY, srcDev, srcX, srcY, srcWidth, srcHeight); } void KisPainter::bitBltOldData(const QPoint & pos, const KisPaintDeviceSP srcDev, const QRect & srcRect) { bitBltOldData(pos.x(), pos.y(), srcDev, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height()); } void KisPainter::fill(qint32 x, qint32 y, qint32 width, qint32 height, const KoColor& color) { /* This check for nonsense ought to be a Q_ASSERT. However, when paintops are just * initializing they perform some dummy passes with those parameters, and it must not crash */ if(width == 0 || height == 0 || d->device.isNull()) return; KoColor srcColor(color, d->device->compositionSourceColorSpace()); qint32 dstY = y; qint32 rowsRemaining = height; KisRandomAccessorSP dstIt = d->device->createRandomAccessorNG(x, y); if(d->selection) { KisPaintDeviceSP selectionProjection(d->selection->projection()); KisRandomConstAccessorSP maskIt = selectionProjection->createRandomConstAccessorNG(x, y); while(rowsRemaining > 0) { qint32 dstX = x; qint32 columnsRemaining = width; qint32 numContiguousDstRows = dstIt->numContiguousRows(dstY); qint32 numContiguousSelRows = maskIt->numContiguousRows(dstY); qint32 rows = qMin(numContiguousDstRows, numContiguousSelRows); rows = qMin(rows, rowsRemaining); while (columnsRemaining > 0) { qint32 numContiguousDstColumns = dstIt->numContiguousColumns(dstX); qint32 numContiguousSelColumns = maskIt->numContiguousColumns(dstX); qint32 columns = qMin(numContiguousDstColumns, numContiguousSelColumns); columns = qMin(columns, columnsRemaining); qint32 dstRowStride = dstIt->rowStride(dstX, dstY); dstIt->moveTo(dstX, dstY); qint32 maskRowStride = maskIt->rowStride(dstX, dstY); maskIt->moveTo(dstX, dstY); d->paramInfo.dstRowStart = dstIt->rawData(); d->paramInfo.dstRowStride = dstRowStride; d->paramInfo.srcRowStart = srcColor.data(); d->paramInfo.srcRowStride = 0; // srcRowStride is set to zero to use the compositeOp with only a single color pixel d->paramInfo.maskRowStart = maskIt->oldRawData(); d->paramInfo.maskRowStride = maskRowStride; d->paramInfo.rows = rows; d->paramInfo.cols = columns; d->colorSpace->bitBlt(srcColor.colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); dstX += columns; columnsRemaining -= columns; } dstY += rows; rowsRemaining -= rows; } } else { while(rowsRemaining > 0) { qint32 dstX = x; qint32 columnsRemaining = width; qint32 numContiguousDstRows = dstIt->numContiguousRows(dstY); qint32 rows = qMin(numContiguousDstRows, rowsRemaining); while(columnsRemaining > 0) { qint32 numContiguousDstColumns = dstIt->numContiguousColumns(dstX); qint32 columns = qMin(numContiguousDstColumns, columnsRemaining); qint32 dstRowStride = dstIt->rowStride(dstX, dstY); dstIt->moveTo(dstX, dstY); d->paramInfo.dstRowStart = dstIt->rawData(); d->paramInfo.dstRowStride = dstRowStride; d->paramInfo.srcRowStart = srcColor.data(); d->paramInfo.srcRowStride = 0; // srcRowStride is set to zero to use the compositeOp with only a single color pixel d->paramInfo.maskRowStart = 0; d->paramInfo.maskRowStride = 0; d->paramInfo.rows = rows; d->paramInfo.cols = columns; d->colorSpace->bitBlt(srcColor.colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); dstX += columns; columnsRemaining -= columns; } dstY += rows; rowsRemaining -= rows; } } addDirtyRect(QRect(x, y, width, height)); } void KisPainter::bltFixed(qint32 dstX, qint32 dstY, const KisFixedPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight) { /* This check for nonsense ought to be a Q_ASSERT. However, when paintops are just initializing they perform some dummy passes with those parameters, and it must not crash */ if (srcWidth == 0 || srcHeight == 0) return; if (srcDev.isNull()) return; if (d->device.isNull()) return; QRect srcRect = QRect(srcX, srcY, srcWidth, srcHeight); QRect srcBounds = srcDev->bounds(); /* Trying to read outside a KisFixedPaintDevice is inherently wrong and shouldn't be done, so crash if someone attempts to do this. Don't resize as it would obfuscate the mistake. */ KIS_SAFE_ASSERT_RECOVER_RETURN(srcBounds.contains(srcRect)); Q_UNUSED(srcRect); // only used in above assertion /* Create an intermediate byte array to hold information before it is written to the current paint device (aka: d->device) */ quint8* dstBytes = 0; try { dstBytes = new quint8[srcWidth * srcHeight * d->device->pixelSize()]; } catch (const std::bad_alloc&) { warnKrita << "KisPainter::bltFixed std::bad_alloc for " << srcWidth << " * " << srcHeight << " * " << d->device->pixelSize() << "total bytes"; return; } d->device->readBytes(dstBytes, dstX, dstY, srcWidth, srcHeight); const quint8 *srcRowStart = srcDev->data() + (srcBounds.width() * (srcY - srcBounds.top()) + (srcX - srcBounds.left())) * srcDev->pixelSize(); d->paramInfo.dstRowStart = dstBytes; d->paramInfo.dstRowStride = srcWidth * d->device->pixelSize(); d->paramInfo.srcRowStart = srcRowStart; d->paramInfo.srcRowStride = srcBounds.width() * srcDev->pixelSize(); d->paramInfo.maskRowStart = 0; d->paramInfo.maskRowStride = 0; d->paramInfo.rows = srcHeight; d->paramInfo.cols = srcWidth; if (d->selection) { /* d->selection is a KisPaintDevice, so first a readBytes is performed to get the area of interest... */ KisPaintDeviceSP selectionProjection(d->selection->projection()); quint8* selBytes = 0; try { selBytes = new quint8[srcWidth * srcHeight * selectionProjection->pixelSize()]; } catch (const std::bad_alloc&) { delete[] dstBytes; return; } selectionProjection->readBytes(selBytes, dstX, dstY, srcWidth, srcHeight); d->paramInfo.maskRowStart = selBytes; d->paramInfo.maskRowStride = srcWidth * selectionProjection->pixelSize(); } // ...and then blit. d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); d->device->writeBytes(dstBytes, dstX, dstY, srcWidth, srcHeight); delete[] d->paramInfo.maskRowStart; delete[] dstBytes; addDirtyRect(QRect(dstX, dstY, srcWidth, srcHeight)); } void KisPainter::bltFixed(const QPoint & pos, const KisFixedPaintDeviceSP srcDev, const QRect & srcRect) { bltFixed(pos.x(), pos.y(), srcDev, srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height()); } void KisPainter::bltFixedWithFixedSelection(qint32 dstX, qint32 dstY, const KisFixedPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, qint32 selX, qint32 selY, qint32 srcX, qint32 srcY, quint32 srcWidth, quint32 srcHeight) { // TODO: get selX and selY working as intended /* This check for nonsense ought to be a Q_ASSERT. However, when paintops are just initializing they perform some dummy passes with those parameters, and it must not crash */ if (srcWidth == 0 || srcHeight == 0) return; if (srcDev.isNull()) return; if (d->device.isNull()) return; // Check that selection has an alpha colorspace, crash if false Q_ASSERT(selection->colorSpace() == KoColorSpaceRegistry::instance()->alpha8()); QRect srcRect = QRect(srcX, srcY, srcWidth, srcHeight); QRect selRect = QRect(selX, selY, srcWidth, srcHeight); QRect srcBounds = srcDev->bounds(); QRect selBounds = selection->bounds(); /* Trying to read outside a KisFixedPaintDevice is inherently wrong and shouldn't be done, so crash if someone attempts to do this. Don't resize as it would obfuscate the mistake. */ Q_ASSERT(srcBounds.contains(srcRect)); Q_UNUSED(srcRect); // only used in above assertion Q_ASSERT(selBounds.contains(selRect)); Q_UNUSED(selRect); // only used in above assertion /* Create an intermediate byte array to hold information before it is written to the current paint device (aka: d->device) */ quint8* dstBytes = 0; try { dstBytes = new quint8[srcWidth * srcHeight * d->device->pixelSize()]; } catch (const std::bad_alloc&) { warnKrita << "KisPainter::bltFixedWithFixedSelection std::bad_alloc for " << srcWidth << " * " << srcHeight << " * " << d->device->pixelSize() << "total bytes"; return; } d->device->readBytes(dstBytes, dstX, dstY, srcWidth, srcHeight); const quint8 *srcRowStart = srcDev->data() + (srcBounds.width() * (srcY - srcBounds.top()) + (srcX - srcBounds.left())) * srcDev->pixelSize(); const quint8 *selRowStart = selection->data() + (selBounds.width() * (selY - selBounds.top()) + (selX - selBounds.left())) * selection->pixelSize(); if (!d->selection) { /* As there's nothing selected, blit to dstBytes (intermediary bit array), ignoring d->selection (the user selection)*/ d->paramInfo.dstRowStart = dstBytes; d->paramInfo.dstRowStride = srcWidth * d->device->pixelSize(); d->paramInfo.srcRowStart = srcRowStart; d->paramInfo.srcRowStride = srcBounds.width() * srcDev->pixelSize(); d->paramInfo.maskRowStart = selRowStart; d->paramInfo.maskRowStride = selBounds.width() * selection->pixelSize(); d->paramInfo.rows = srcHeight; d->paramInfo.cols = srcWidth; d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); } else { /* Read the user selection (d->selection) bytes into an array, ready to merge in the next block*/ quint32 totalBytes = srcWidth * srcHeight * selection->pixelSize(); quint8 * mergedSelectionBytes = 0; try { mergedSelectionBytes = new quint8[ totalBytes ]; } catch (const std::bad_alloc&) { warnKrita << "KisPainter::bltFixedWithFixedSelection std::bad_alloc for " << totalBytes << "total bytes"; delete[] dstBytes; return; } d->selection->projection()->readBytes(mergedSelectionBytes, dstX, dstY, srcWidth, srcHeight); // Merge selections here by multiplying them - compositeOp(COMPOSITE_MULT) d->paramInfo.dstRowStart = mergedSelectionBytes; d->paramInfo.dstRowStride = srcWidth * selection->pixelSize(); d->paramInfo.srcRowStart = selRowStart; d->paramInfo.srcRowStride = selBounds.width() * selection->pixelSize(); d->paramInfo.maskRowStart = 0; d->paramInfo.maskRowStride = 0; d->paramInfo.rows = srcHeight; d->paramInfo.cols = srcWidth; KoColorSpaceRegistry::instance()->alpha8()->compositeOp(COMPOSITE_MULT)->composite(d->paramInfo); // Blit to dstBytes (intermediary bit array) d->paramInfo.dstRowStart = dstBytes; d->paramInfo.dstRowStride = srcWidth * d->device->pixelSize(); d->paramInfo.srcRowStart = srcRowStart; d->paramInfo.srcRowStride = srcBounds.width() * srcDev->pixelSize(); d->paramInfo.maskRowStart = mergedSelectionBytes; d->paramInfo.maskRowStride = srcWidth * selection->pixelSize(); d->colorSpace->bitBlt(srcDev->colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); delete[] mergedSelectionBytes; } d->device->writeBytes(dstBytes, dstX, dstY, srcWidth, srcHeight); delete[] dstBytes; addDirtyRect(QRect(dstX, dstY, srcWidth, srcHeight)); } void KisPainter::bltFixedWithFixedSelection(qint32 dstX, qint32 dstY, const KisFixedPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, quint32 srcWidth, quint32 srcHeight) { bltFixedWithFixedSelection(dstX, dstY, srcDev, selection, 0, 0, 0, 0, srcWidth, srcHeight); } void KisPainter::paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance) { if (d->device && d->paintOp && d->paintOp->canPaint()) { d->paintOp->paintLine(pi1, pi2, currentDistance); } } void KisPainter::paintPolyline(const vQPointF &points, int index, int numPoints) { if (d->fillStyle != FillStyleNone) { fillPolygon(points, d->fillStyle); } if (index >= points.count()) return; if (numPoints < 0) numPoints = points.count(); if (index + numPoints > points.count()) numPoints = points.count() - index; if (numPoints > 1) { KisDistanceInformation saveDist(points[0], KisAlgebra2D::directionBetweenPoints(points[0], points[1], 0.0)); for (int i = index; i < index + numPoints - 1; i++) { paintLine(points [i], points [i + 1], &saveDist); } } } static void getBezierCurvePoints(const KisVector2D &pos1, const KisVector2D &control1, const KisVector2D &control2, const KisVector2D &pos2, vQPointF& points) { LineEquation line = LineEquation::Through(pos1, pos2); qreal d1 = line.absDistance(control1); qreal d2 = line.absDistance(control2); if (d1 < BEZIER_FLATNESS_THRESHOLD && d2 < BEZIER_FLATNESS_THRESHOLD) { points.push_back(toQPointF(pos1)); } else { // Midpoint subdivision. See Foley & Van Dam Computer Graphics P.508 KisVector2D l2 = (pos1 + control1) / 2; KisVector2D h = (control1 + control2) / 2; KisVector2D l3 = (l2 + h) / 2; KisVector2D r3 = (control2 + pos2) / 2; KisVector2D r2 = (h + r3) / 2; KisVector2D l4 = (l3 + r2) / 2; getBezierCurvePoints(pos1, l2, l3, l4, points); getBezierCurvePoints(l4, r2, r3, pos2, points); } } void KisPainter::getBezierCurvePoints(const QPointF &pos1, const QPointF &control1, const QPointF &control2, const QPointF &pos2, vQPointF& points) const { ::getBezierCurvePoints(toKisVector2D(pos1), toKisVector2D(control1), toKisVector2D(control2), toKisVector2D(pos2), points); } void KisPainter::paintBezierCurve(const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance) { if (d->paintOp && d->paintOp->canPaint()) { d->paintOp->paintBezierCurve(pi1, control1, control2, pi2, currentDistance); } } void KisPainter::paintRect(const QRectF &rect) { QRectF normalizedRect = rect.normalized(); vQPointF points; points.push_back(normalizedRect.topLeft()); points.push_back(normalizedRect.bottomLeft()); points.push_back(normalizedRect.bottomRight()); points.push_back(normalizedRect.topRight()); paintPolygon(points); } void KisPainter::paintRect(const qreal x, const qreal y, const qreal w, const qreal h) { paintRect(QRectF(x, y, w, h)); } void KisPainter::paintEllipse(const QRectF &rect) { QRectF r = rect.normalized(); // normalize before checking as negative width and height are empty too if (r.isEmpty()) return; // See http://www.whizkidtech.redprince.net/bezier/circle/ for explanation. // kappa = (4/3*(sqrt(2)-1)) const qreal kappa = 0.5522847498; const qreal lx = (r.width() / 2) * kappa; const qreal ly = (r.height() / 2) * kappa; QPointF center = r.center(); QPointF p0(r.left(), center.y()); QPointF p1(r.left(), center.y() - ly); QPointF p2(center.x() - lx, r.top()); QPointF p3(center.x(), r.top()); vQPointF points; getBezierCurvePoints(p0, p1, p2, p3, points); QPointF p4(center.x() + lx, r.top()); QPointF p5(r.right(), center.y() - ly); QPointF p6(r.right(), center.y()); getBezierCurvePoints(p3, p4, p5, p6, points); QPointF p7(r.right(), center.y() + ly); QPointF p8(center.x() + lx, r.bottom()); QPointF p9(center.x(), r.bottom()); getBezierCurvePoints(p6, p7, p8, p9, points); QPointF p10(center.x() - lx, r.bottom()); QPointF p11(r.left(), center.y() + ly); getBezierCurvePoints(p9, p10, p11, p0, points); paintPolygon(points); } void KisPainter::paintEllipse(const qreal x, const qreal y, const qreal w, const qreal h) { paintEllipse(QRectF(x, y, w, h)); } void KisPainter::paintAt(const KisPaintInformation& pi, KisDistanceInformation *savedDist) { if (d->paintOp && d->paintOp->canPaint()) { d->paintOp->paintAt(pi, savedDist); } } void KisPainter::fillPolygon(const vQPointF& points, FillStyle fillStyle) { if (points.count() < 3) { return; } if (fillStyle == FillStyleNone) { return; } QPainterPath polygonPath; polygonPath.moveTo(points.at(0)); for (int pointIndex = 1; pointIndex < points.count(); pointIndex++) { polygonPath.lineTo(points.at(pointIndex)); } polygonPath.closeSubpath(); d->fillStyle = fillStyle; fillPainterPath(polygonPath); } void KisPainter::paintPolygon(const vQPointF& points) { if (d->fillStyle != FillStyleNone) { fillPolygon(points, d->fillStyle); } if (d->strokeStyle != StrokeStyleNone) { if (points.count() > 1) { KisDistanceInformation distance(points[0], KisAlgebra2D::directionBetweenPoints(points[0], points[1], 0.0)); for (int i = 0; i < points.count() - 1; i++) { paintLine(KisPaintInformation(points[i]), KisPaintInformation(points[i + 1]), &distance); } paintLine(points[points.count() - 1], points[0], &distance); } } } void KisPainter::paintPainterPath(const QPainterPath& path) { if (d->fillStyle != FillStyleNone) { fillPainterPath(path); } if (d->strokeStyle == StrokeStyleNone) return; QPointF lastPoint, nextPoint; int elementCount = path.elementCount(); KisDistanceInformation saveDist; for (int i = 0; i < elementCount; i++) { QPainterPath::Element element = path.elementAt(i); switch (element.type) { case QPainterPath::MoveToElement: lastPoint = QPointF(element.x, element.y); break; case QPainterPath::LineToElement: nextPoint = QPointF(element.x, element.y); paintLine(KisPaintInformation(lastPoint), KisPaintInformation(nextPoint), &saveDist); lastPoint = nextPoint; break; case QPainterPath::CurveToElement: nextPoint = QPointF(path.elementAt(i + 2).x, path.elementAt(i + 2).y); paintBezierCurve(KisPaintInformation(lastPoint), QPointF(path.elementAt(i).x, path.elementAt(i).y), QPointF(path.elementAt(i + 1).x, path.elementAt(i + 1).y), KisPaintInformation(nextPoint), &saveDist); lastPoint = nextPoint; break; default: continue; } } } void KisPainter::fillPainterPath(const QPainterPath& path) { fillPainterPath(path, QRect()); } void KisPainter::fillPainterPath(const QPainterPath& path, const QRect &requestedRect) { if (d->mirrorHorizontally || d->mirrorVertically) { KisLodTransform lod(d->device); QPointF effectiveAxesCenter = lod.map(d->axesCenter); QTransform C1 = QTransform::fromTranslate(-effectiveAxesCenter.x(), -effectiveAxesCenter.y()); QTransform C2 = QTransform::fromTranslate(effectiveAxesCenter.x(), effectiveAxesCenter.y()); QTransform t; QPainterPath newPath; QRect newRect; if (d->mirrorHorizontally) { t = C1 * QTransform::fromScale(-1,1) * C2; newPath = t.map(path); newRect = t.mapRect(requestedRect); d->fillPainterPathImpl(newPath, newRect); } if (d->mirrorVertically) { t = C1 * QTransform::fromScale(1,-1) * C2; newPath = t.map(path); newRect = t.mapRect(requestedRect); d->fillPainterPathImpl(newPath, newRect); } if (d->mirrorHorizontally && d->mirrorVertically) { t = C1 * QTransform::fromScale(-1,-1) * C2; newPath = t.map(path); newRect = t.mapRect(requestedRect); d->fillPainterPathImpl(newPath, newRect); } } d->fillPainterPathImpl(path, requestedRect); } void KisPainter::Private::fillPainterPathImpl(const QPainterPath& path, const QRect &requestedRect) { if (fillStyle == FillStyleNone) { return; } // Fill the polygon bounding rectangle with the required contents then we'll // create a mask for the actual polygon coverage. if (!fillPainter) { polygon = device->createCompositionSourceDevice(); fillPainter = new KisFillPainter(polygon); } else { polygon->clear(); } Q_CHECK_PTR(polygon); QRectF boundingRect = path.boundingRect(); QRect fillRect = boundingRect.toAlignedRect(); // Expand the rectangle to allow for anti-aliasing. fillRect.adjust(-1, -1, 1, 1); if (requestedRect.isValid()) { fillRect &= requestedRect; } switch (fillStyle) { default: /* Falls through. */ case FillStyleGradient: // Currently unsupported /* Falls through. */ case FillStyleStrokes: // Currently unsupported warnImage << "Unknown or unsupported fill style in fillPolygon\n"; /* Falls through. */ case FillStyleForegroundColor: fillPainter->fillRect(fillRect, q->paintColor(), OPACITY_OPAQUE_U8); break; case FillStyleBackgroundColor: fillPainter->fillRect(fillRect, q->backgroundColor(), OPACITY_OPAQUE_U8); break; case FillStylePattern: if (pattern) { // if the user hasn't got any patterns installed, we shouldn't crash... fillPainter->fillRect(fillRect, pattern); } break; case FillStyleGenerator: if (generator) { // if the user hasn't got any generators, we shouldn't crash... fillPainter->fillRect(fillRect.x(), fillRect.y(), fillRect.width(), fillRect.height(), q->generator()); } break; } if (polygonMaskImage.isNull() || (maskPainter == 0)) { polygonMaskImage = QImage(maskImageWidth, maskImageHeight, QImage::Format_ARGB32_Premultiplied); maskPainter = new QPainter(&polygonMaskImage); maskPainter->setRenderHint(QPainter::Antialiasing, q->antiAliasPolygonFill()); } // Break the mask up into chunks so we don't have to allocate a potentially very large QImage. const QColor black(Qt::black); const QBrush brush(Qt::white); for (qint32 x = fillRect.x(); x < fillRect.x() + fillRect.width(); x += maskImageWidth) { for (qint32 y = fillRect.y(); y < fillRect.y() + fillRect.height(); y += maskImageHeight) { polygonMaskImage.fill(black.rgb()); maskPainter->translate(-x, -y); maskPainter->fillPath(path, brush); maskPainter->translate(x, y); qint32 rectWidth = qMin(fillRect.x() + fillRect.width() - x, maskImageWidth); qint32 rectHeight = qMin(fillRect.y() + fillRect.height() - y, maskImageHeight); KisHLineIteratorSP lineIt = polygon->createHLineIteratorNG(x, y, rectWidth); quint8 tmp; for (int row = y; row < y + rectHeight; row++) { QRgb* line = reinterpret_cast(polygonMaskImage.scanLine(row - y)); do { tmp = qRed(line[lineIt->x() - x]); polygon->colorSpace()->applyAlphaU8Mask(lineIt->rawData(), &tmp, 1); } while (lineIt->nextPixel()); lineIt->nextRow(); } } } QRect bltRect = !requestedRect.isEmpty() ? requestedRect : fillRect; q->bitBlt(bltRect.x(), bltRect.y(), polygon, bltRect.x(), bltRect.y(), bltRect.width(), bltRect.height()); } void KisPainter::drawPainterPath(const QPainterPath& path, const QPen& pen) { drawPainterPath(path, pen, QRect()); } void KisPainter::drawPainterPath(const QPainterPath& path, const QPen& pen, const QRect &requestedRect) { // we are drawing mask, it has to be white // color of the path is given by paintColor() Q_ASSERT(pen.color() == Qt::white); if (!d->fillPainter) { d->polygon = d->device->createCompositionSourceDevice(); d->fillPainter = new KisFillPainter(d->polygon); } else { d->polygon->clear(); } Q_CHECK_PTR(d->polygon); QRectF boundingRect = path.boundingRect(); QRect fillRect = boundingRect.toAlignedRect(); // take width of the pen into account int penWidth = qRound(pen.widthF()); fillRect.adjust(-penWidth, -penWidth, penWidth, penWidth); // Expand the rectangle to allow for anti-aliasing. fillRect.adjust(-1, -1, 1, 1); if (!requestedRect.isNull()) { fillRect &= requestedRect; } d->fillPainter->fillRect(fillRect, paintColor(), OPACITY_OPAQUE_U8); if (d->polygonMaskImage.isNull() || (d->maskPainter == 0)) { d->polygonMaskImage = QImage(d->maskImageWidth, d->maskImageHeight, QImage::Format_ARGB32_Premultiplied); d->maskPainter = new QPainter(&d->polygonMaskImage); d->maskPainter->setRenderHint(QPainter::Antialiasing, antiAliasPolygonFill()); } // Break the mask up into chunks so we don't have to allocate a potentially very large QImage. const QColor black(Qt::black); QPen oldPen = d->maskPainter->pen(); d->maskPainter->setPen(pen); for (qint32 x = fillRect.x(); x < fillRect.x() + fillRect.width(); x += d->maskImageWidth) { for (qint32 y = fillRect.y(); y < fillRect.y() + fillRect.height(); y += d->maskImageHeight) { d->polygonMaskImage.fill(black.rgb()); d->maskPainter->translate(-x, -y); d->maskPainter->drawPath(path); d->maskPainter->translate(x, y); qint32 rectWidth = qMin(fillRect.x() + fillRect.width() - x, d->maskImageWidth); qint32 rectHeight = qMin(fillRect.y() + fillRect.height() - y, d->maskImageHeight); KisHLineIteratorSP lineIt = d->polygon->createHLineIteratorNG(x, y, rectWidth); quint8 tmp; for (int row = y; row < y + rectHeight; row++) { QRgb* line = reinterpret_cast(d->polygonMaskImage.scanLine(row - y)); do { tmp = qRed(line[lineIt->x() - x]); d->polygon->colorSpace()->applyAlphaU8Mask(lineIt->rawData(), &tmp, 1); } while (lineIt->nextPixel()); lineIt->nextRow(); } } } d->maskPainter->setPen(oldPen); QRect r = d->polygon->extent(); bitBlt(r.x(), r.y(), d->polygon, r.x(), r.y(), r.width(), r.height()); } inline void KisPainter::compositeOnePixel(quint8 *dst, const KoColor &color) { d->paramInfo.dstRowStart = dst; d->paramInfo.dstRowStride = 0; d->paramInfo.srcRowStart = color.data(); d->paramInfo.srcRowStride = 0; d->paramInfo.maskRowStart = 0; d->paramInfo.maskRowStride = 0; d->paramInfo.rows = 1; d->paramInfo.cols = 1; d->colorSpace->bitBlt(color.colorSpace(), d->paramInfo, d->compositeOp, d->renderingIntent, d->conversionFlags); } /**/ void KisPainter::drawLine(const QPointF& start, const QPointF& end, qreal width, bool antialias){ int x1 = qFloor(start.x()); int y1 = qFloor(start.y()); int x2 = qFloor(end.x()); int y2 = qFloor(end.y()); if ((x2 == x1 ) && (y2 == y1)) return; int dstX = x2-x1; int dstY = y2-y1; qreal uniC = dstX*y1 - dstY*x1; qreal projectionDenominator = 1.0 / (pow((double)dstX, 2) + pow((double)dstY, 2)); qreal subPixel; if (qAbs(dstX) > qAbs(dstY)){ subPixel = start.x() - x1; }else{ subPixel = start.y() - y1; } qreal halfWidth = width * 0.5 + subPixel; int W_ = qRound(halfWidth) + 1; // save the state int X1_ = x1; int Y1_ = y1; int X2_ = x2; int Y2_ = y2; if (x2device->createRandomAccessorNG(x1, y1); KisRandomConstAccessorSP selectionAccessor; if (d->selection) { selectionAccessor = d->selection->projection()->createRandomConstAccessorNG(x1, y1); } for (int y = y1-W_; y < y2+W_ ; y++){ for (int x = x1-W_; x < x2+W_; x++){ projection = ( (x-X1_)* dstX + (y-Y1_)*dstY ) * projectionDenominator; scanX = X1_ + projection * dstX; scanY = Y1_ + projection * dstY; if (((scanX < x1) || (scanX > x2)) || ((scanY < y1) || (scanY > y2))) { AA_ = qMin( sqrt( pow((double)x - X1_, 2) + pow((double)y - Y1_, 2) ), sqrt( pow((double)x - X2_, 2) + pow((double)y - Y2_, 2) )); }else{ AA_ = qAbs(dstY*x - dstX*y + uniC) * denominator; } if (AA_>halfWidth) { continue; } accessor->moveTo(x, y); if (selectionAccessor) selectionAccessor->moveTo(x,y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { KoColor mycolor = d->paintColor; if (antialias && AA_ > halfWidth-1.0) { mycolor.colorSpace()->multiplyAlpha(mycolor.data(), 1.0 - (AA_-(halfWidth-1.0)), 1); } compositeOnePixel(accessor->rawData(), mycolor); } } } } /**/ void KisPainter::drawLine(const QPointF & start, const QPointF & end) { drawThickLine(start, end, 1, 1); } void KisPainter::drawDDALine(const QPointF & start, const QPointF & end) { int x = qFloor(start.x()); int y = qFloor(start.y()); int x2 = qFloor(end.x()); int y2 = qFloor(end.y()); // Width and height of the line int xd = x2 - x; int yd = y2 - y; float m = (float)yd / (float)xd; float fx = x; float fy = y; int inc; KisRandomAccessorSP accessor = d->device->createRandomAccessorNG(x, y); KisRandomConstAccessorSP selectionAccessor; if (d->selection) { selectionAccessor = d->selection->projection()->createRandomConstAccessorNG(x, y); } accessor->moveTo(x, y); if (selectionAccessor) selectionAccessor->moveTo(x,y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), d->paintColor); } if (fabs(m) > 1.0f) { inc = (yd > 0) ? 1 : -1; m = 1.0f / m; m *= inc; while (y != y2) { y = y + inc; fx = fx + m; x = qRound(fx); accessor->moveTo(x, y); if (selectionAccessor) selectionAccessor->moveTo(x, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), d->paintColor); } } } else { inc = (xd > 0) ? 1 : -1; m *= inc; while (x != x2) { x = x + inc; fy = fy + m; y = qRound(fy); accessor->moveTo(x, y); if (selectionAccessor) selectionAccessor->moveTo(x, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), d->paintColor); } } } } void KisPainter::drawWobblyLine(const QPointF & start, const QPointF & end) { KoColor mycolor(d->paintColor); int x1 = qFloor(start.x()); int y1 = qFloor(start.y()); int x2 = qFloor(end.x()); int y2 = qFloor(end.y()); KisRandomAccessorSP accessor = d->device->createRandomAccessorNG(x1, y1); KisRandomConstAccessorSP selectionAccessor; if (d->selection) { selectionAccessor = d->selection->projection()->createRandomConstAccessorNG(x1, y1); } // Width and height of the line int xd = (x2 - x1); int yd = (y2 - y1); int x; int y; float fx = (x = x1); float fy = (y = y1); float m = (float)yd / (float)xd; int inc; if (fabs(m) > 1) { inc = (yd > 0) ? 1 : -1; m = 1.0f / m; m *= inc; while (y != y2) { fx = fx + m; y = y + inc; x = qRound(fx); float br1 = qFloor(fx + 1) - fx; float br2 = fx - qFloor(fx); accessor->moveTo(x, y); if (selectionAccessor) selectionAccessor->moveTo(x, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { mycolor.setOpacity((quint8)(255*br1)); compositeOnePixel(accessor->rawData(), mycolor); } accessor->moveTo(x + 1, y); if (selectionAccessor) selectionAccessor->moveTo(x + 1, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { mycolor.setOpacity((quint8)(255*br2)); compositeOnePixel(accessor->rawData(), mycolor); } } } else { inc = (xd > 0) ? 1 : -1; m *= inc; while (x != x2) { fy = fy + m; x = x + inc; y = qRound(fy); float br1 = qFloor(fy + 1) - fy; float br2 = fy - qFloor(fy); accessor->moveTo(x, y); if (selectionAccessor) selectionAccessor->moveTo(x, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { mycolor.setOpacity((quint8)(255*br1)); compositeOnePixel(accessor->rawData(), mycolor); } accessor->moveTo(x, y + 1); if (selectionAccessor) selectionAccessor->moveTo(x, y + 1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { mycolor.setOpacity((quint8)(255*br2)); compositeOnePixel(accessor->rawData(), mycolor); } } } } void KisPainter::drawWuLine(const QPointF & start, const QPointF & end) { KoColor lineColor(d->paintColor); int x1 = qFloor(start.x()); int y1 = qFloor(start.y()); int x2 = qFloor(end.x()); int y2 = qFloor(end.y()); KisRandomAccessorSP accessor = d->device->createRandomAccessorNG(x1, y1); KisRandomConstAccessorSP selectionAccessor; if (d->selection) { selectionAccessor = d->selection->projection()->createRandomConstAccessorNG(x1, y1); } float grad, xd, yd; float xgap, ygap, xend, yend, yf, xf; float brightness1, brightness2; int ix1, ix2, iy1, iy2; quint8 c1, c2; // gradient of line xd = (x2 - x1); yd = (y2 - y1); if (yd == 0) { /* Horizontal line */ int incr = (x1 < x2) ? 1 : -1; ix1 = x1; ix2 = x2; iy1 = y1; while (ix1 != ix2) { ix1 = ix1 + incr; accessor->moveTo(ix1, iy1); if (selectionAccessor) selectionAccessor->moveTo(ix1, iy1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), lineColor); } } return; } if (xd == 0) { /* Vertical line */ int incr = (y1 < y2) ? 1 : -1; iy1 = y1; iy2 = y2; ix1 = x1; while (iy1 != iy2) { iy1 = iy1 + incr; accessor->moveTo(ix1, iy1); if (selectionAccessor) selectionAccessor->moveTo(ix1, iy1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), lineColor); } } return; } if (fabs(xd) > fabs(yd)) { // horizontal line // line have to be paint from left to right if (x1 > x2) { std::swap(x1, x2); std::swap(y1, y2); xd = (x2 - x1); yd = (y2 - y1); } grad = yd / xd; // nearest X,Y integer coordinates xend = x1; yend = y1 + grad * (xend - x1); xgap = invertFrac(x1 + 0.5f); ix1 = x1; iy1 = qFloor(yend); // calc the intensity of the other end point pixel pair. brightness1 = invertFrac(yend) * xgap; brightness2 = frac(yend) * xgap; c1 = (int)(brightness1 * OPACITY_OPAQUE_U8); c2 = (int)(brightness2 * OPACITY_OPAQUE_U8); accessor->moveTo(ix1, iy1); if (selectionAccessor) selectionAccessor->moveTo(ix1, iy1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c1); compositeOnePixel(accessor->rawData(), lineColor); } accessor->moveTo(ix1, iy1 + 1); if (selectionAccessor) selectionAccessor->moveTo(ix1, iy1 + 1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c2); compositeOnePixel(accessor->rawData(), lineColor); } // calc first Y-intersection for main loop yf = yend + grad; xend = x2; yend = y2 + grad * (xend - x2); xgap = invertFrac(x2 - 0.5f); ix2 = x2; iy2 = qFloor(yend); brightness1 = invertFrac(yend) * xgap; brightness2 = frac(yend) * xgap; c1 = (int)(brightness1 * OPACITY_OPAQUE_U8); c2 = (int)(brightness2 * OPACITY_OPAQUE_U8); accessor->moveTo(ix2, iy2); if (selectionAccessor) selectionAccessor->moveTo(ix2, iy2); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c1); compositeOnePixel(accessor->rawData(), lineColor); } accessor->moveTo(ix2, iy2 + 1); if (selectionAccessor) selectionAccessor->moveTo(ix2, iy2 + 1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c2); compositeOnePixel(accessor->rawData(), lineColor); } // main loop for (int x = ix1 + 1; x <= ix2 - 1; x++) { brightness1 = invertFrac(yf); brightness2 = frac(yf); c1 = (int)(brightness1 * OPACITY_OPAQUE_U8); c2 = (int)(brightness2 * OPACITY_OPAQUE_U8); accessor->moveTo(x, qFloor(yf)); if (selectionAccessor) selectionAccessor->moveTo(x, qFloor(yf)); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c1); compositeOnePixel(accessor->rawData(), lineColor); } accessor->moveTo(x, qFloor(yf) + 1); if (selectionAccessor) selectionAccessor->moveTo(x, qFloor(yf) + 1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c2); compositeOnePixel(accessor->rawData(), lineColor); } yf = yf + grad; } } else { //vertical // line have to be painted from left to right if (y1 > y2) { std::swap(x1, x2); std::swap(y1, y2); xd = (x2 - x1); yd = (y2 - y1); } grad = xd / yd; // nearest X,Y integer coordinates yend = y1; xend = x1 + grad * (yend - y1); ygap = y1; ix1 = qFloor(xend); iy1 = y1; // calc the intensity of the other end point pixel pair. brightness1 = invertFrac(xend) * ygap; brightness2 = frac(xend) * ygap; c1 = (int)(brightness1 * OPACITY_OPAQUE_U8); c2 = (int)(brightness2 * OPACITY_OPAQUE_U8); accessor->moveTo(ix1, iy1); if (selectionAccessor) selectionAccessor->moveTo(ix1, iy1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c1); compositeOnePixel(accessor->rawData(), lineColor); } accessor->moveTo(x1 + 1, y1); if (selectionAccessor) selectionAccessor->moveTo(x1 + 1, y1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c2); compositeOnePixel(accessor->rawData(), lineColor); } // calc first Y-intersection for main loop xf = xend + grad; yend = y2; xend = x2 + grad * (yend - y2); ygap = invertFrac(y2 - 0.5f); ix2 = qFloor(xend); iy2 = y2; brightness1 = invertFrac(xend) * ygap; brightness2 = frac(xend) * ygap; c1 = (int)(brightness1 * OPACITY_OPAQUE_U8); c2 = (int)(brightness2 * OPACITY_OPAQUE_U8); accessor->moveTo(ix2, iy2); if (selectionAccessor) selectionAccessor->moveTo(ix2, iy2); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c1); compositeOnePixel(accessor->rawData(), lineColor); } accessor->moveTo(ix2 + 1, iy2); if (selectionAccessor) selectionAccessor->moveTo(ix2 + 1, iy2); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c2); compositeOnePixel(accessor->rawData(), lineColor); } // main loop for (int y = iy1 + 1; y <= iy2 - 1; y++) { brightness1 = invertFrac(xf); brightness2 = frac(xf); c1 = (int)(brightness1 * OPACITY_OPAQUE_U8); c2 = (int)(brightness2 * OPACITY_OPAQUE_U8); accessor->moveTo(qFloor(xf), y); if (selectionAccessor) selectionAccessor->moveTo(qFloor(xf), y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c1); compositeOnePixel(accessor->rawData(), lineColor); } accessor->moveTo(qFloor(xf) + 1, y); if (selectionAccessor) selectionAccessor->moveTo(qFloor(xf) + 1, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { lineColor.setOpacity(c2); compositeOnePixel(accessor->rawData(), lineColor); } xf = xf + grad; } }//end-of-else } void KisPainter::drawThickLine(const QPointF & start, const QPointF & end, int startWidth, int endWidth) { KisRandomAccessorSP accessor = d->device->createRandomAccessorNG(start.x(), start.y()); KisRandomConstAccessorSP selectionAccessor; if (d->selection) { selectionAccessor = d->selection->projection()->createRandomConstAccessorNG(start.x(), start.y()); } const KoColorSpace *cs = d->device->colorSpace(); KoColor c1(d->paintColor); KoColor c2(d->paintColor); KoColor c3(d->paintColor); KoColor col1(c1); KoColor col2(c1); float grada, gradb, dxa, dxb, dya, dyb, fraca, fracb, xfa, yfa, xfb, yfb, b1a, b2a, b1b, b2b, dstX, dstY; int x, y, ix1, ix2, iy1, iy2; int x0a, y0a, x1a, y1a, x0b, y0b, x1b, y1b; int tp0, tn0, tp1, tn1; int horizontal = 0; float opacity = 1.0; tp0 = startWidth / 2; tn0 = startWidth / 2; if (startWidth % 2 == 0) // even width startWidth tn0--; tp1 = endWidth / 2; tn1 = endWidth / 2; if (endWidth % 2 == 0) // even width endWidth tn1--; int x0 = qRound(start.x()); int y0 = qRound(start.y()); int x1 = qRound(end.x()); int y1 = qRound(end.y()); dstX = x1 - x0; // run of general line dstY = y1 - y0; // rise of general line if (dstY < 0) dstY = -dstY; if (dstX < 0) dstX = -dstX; if (dstX > dstY) { // horizontalish horizontal = 1; x0a = x0; y0a = y0 - tn0; x0b = x0; y0b = y0 + tp0; x1a = x1; y1a = y1 - tn1; x1b = x1; y1b = y1 + tp1; } else { x0a = x0 - tn0; y0a = y0; x0b = x0 + tp0; y0b = y0; x1a = x1 - tn1; y1a = y1; x1b = x1 + tp1; y1b = y1; } if (horizontal) { // draw endpoints for (int i = y0a; i <= y0b; i++) { accessor->moveTo(x0, i); if (selectionAccessor) selectionAccessor->moveTo(x0, i); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), c1); } } for (int i = y1a; i <= y1b; i++) { accessor->moveTo(x1, i); if (selectionAccessor) selectionAccessor->moveTo(x1, i); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), c1); } } } else { for (int i = x0a; i <= x0b; i++) { accessor->moveTo(i, y0); if (selectionAccessor) selectionAccessor->moveTo(i, y0); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), c1); } } for (int i = x1a; i <= x1b; i++) { accessor->moveTo(i, y1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), c1); } } } //antialias endpoints if (x1 != x0 && y1 != y0) { if (horizontal) { accessor->moveTo(x0a, y0a - 1); if (selectionAccessor) selectionAccessor->moveTo(x0a, y0a - 1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = .25 * c1.opacityF() + (1 - .25) * alpha; col1.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col1); } accessor->moveTo(x1b, y1b + 1); if (selectionAccessor) selectionAccessor->moveTo(x1b, y1b + 1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = .25 * c2.opacityF() + (1 - .25) * alpha; col1.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col1); } } else { accessor->moveTo(x0a - 1, y0a); if (selectionAccessor) selectionAccessor->moveTo(x0a - 1, y0a); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = .25 * c1.opacityF() + (1 - .25) * alpha; col1.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col1); } accessor->moveTo(x1b + 1, y1b); if (selectionAccessor) selectionAccessor->moveTo(x1b + 1, y1b); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = .25 * c2.opacityF() + (1 - .25) * alpha; col1.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col1); } } } dxa = x1a - x0a; // run of a dya = y1a - y0a; // rise of a dxb = x1b - x0b; // run of b dyb = y1b - y0b; // rise of b if (horizontal) { // horizontal-ish lines if (x1 < x0) { int xt, yt, wt; KoColor tmp; xt = x1a; x1a = x0a; x0a = xt; yt = y1a; y1a = y0a; y0a = yt; xt = x1b; x1b = x0b; x0b = xt; yt = y1b; y1b = y0b; y0b = yt; xt = x1; x1 = x0; x0 = xt; yt = y1; y1 = y0; y0 = yt; tmp = c1; c1 = c2; c2 = tmp; wt = startWidth; startWidth = endWidth; endWidth = wt; } grada = dya / dxa; gradb = dyb / dxb; ix1 = x0; iy1 = y0; ix2 = x1; iy2 = y1; yfa = y0a + grada; yfb = y0b + gradb; for (x = ix1 + 1; x <= ix2 - 1; x++) { fraca = yfa - qFloor(yfa); b1a = 1 - fraca; b2a = fraca; fracb = yfb - qFloor(yfb); b1b = 1 - fracb; b2b = fracb; // color first pixel of bottom line opacity = ((x - ix1) / dstX) * c2.opacityF() + (1 - (x - ix1) / dstX) * c1.opacityF(); c3.setOpacity(opacity); accessor->moveTo(x, qFloor(yfa)); if (selectionAccessor) selectionAccessor->moveTo(x, qFloor(yfa)); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = b1a * c3.opacityF() + (1 - b1a) * alpha; col1.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col1); } // color first pixel of top line if (!(startWidth == 1 && endWidth == 1)) { accessor->moveTo(x, qFloor(yfb)); if (selectionAccessor) selectionAccessor->moveTo(x, qFloor(yfb)); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = b1b * c3.opacityF() + (1 - b1b) * alpha; col1.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col1); } } // color second pixel of bottom line if (grada != 0 && grada != 1) { // if not flat or exact diagonal accessor->moveTo(x, qFloor(yfa) + 1); if (selectionAccessor) selectionAccessor->moveTo(x, qFloor(yfa) + 1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = b2a * c3.opacityF() + (1 - b2a) * alpha; col2.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col2); } } // color second pixel of top line if (gradb != 0 && gradb != 1 && !(startWidth == 1 && endWidth == 1)) { accessor->moveTo(x, qFloor(yfb) + 1); if (selectionAccessor) selectionAccessor->moveTo(x, qFloor(yfb) + 1); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = b2b * c3.opacityF() + (1 - b2b) * alpha; col2.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col2); } } // fill remaining pixels if (!(startWidth == 1 && endWidth == 1)) { if (yfa < yfb) for (int i = qFloor(yfa) + 1; i <= qFloor(yfb); i++) { accessor->moveTo(x, i); if (selectionAccessor) selectionAccessor->moveTo(x, i); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), c3); } } else for (int i = qFloor(yfa) + 1; i >= qFloor(yfb); i--) { accessor->moveTo(x, i); if (selectionAccessor) selectionAccessor->moveTo(x, i); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), c3); } } } yfa += grada; yfb += gradb; } } else { // vertical-ish lines if (y1 < y0) { int xt, yt, wt; xt = x1a; x1a = x0a; x0a = xt; yt = y1a; y1a = y0a; y0a = yt; xt = x1b; x1b = x0b; x0b = xt; yt = y1b; y1b = y0b; y0b = yt; xt = x1; x1 = x0; x0 = xt; yt = y1; y1 = y0; y0 = yt; KoColor tmp; tmp = c1; c1 = c2; c2 = tmp; wt = startWidth; startWidth = endWidth; endWidth = wt; } grada = dxa / dya; gradb = dxb / dyb; ix1 = x0; iy1 = y0; ix2 = x1; iy2 = y1; xfa = x0a + grada; xfb = x0b + gradb; for (y = iy1 + 1; y <= iy2 - 1; y++) { fraca = xfa - qFloor(xfa); b1a = 1 - fraca; b2a = fraca; fracb = xfb - qFloor(xfb); b1b = 1 - fracb; b2b = fracb; // color first pixel of left line opacity = ((y - iy1) / dstY) * c2.opacityF() + (1 - (y - iy1) / dstY) * c1.opacityF(); c3.setOpacity(opacity); accessor->moveTo(qFloor(xfa), y); if (selectionAccessor) selectionAccessor->moveTo(qFloor(xfa), y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = b1a * c3.opacityF() + (1 - b1a) * alpha; col1.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col1); } // color first pixel of right line if (!(startWidth == 1 && endWidth == 1)) { accessor->moveTo(qFloor(xfb), y); if (selectionAccessor) selectionAccessor->moveTo(qFloor(xfb), y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = b1b * c3.opacityF() + (1 - b1b) * alpha; col1.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col1); } } // color second pixel of left line if (grada != 0 && grada != 1) { // if not flat or exact diagonal accessor->moveTo(qFloor(xfa) + 1, y); if (selectionAccessor) selectionAccessor->moveTo(qFloor(xfa) + 1, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = b2a * c3.opacityF() + (1 - b2a) * alpha; col2.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col2); } } // color second pixel of right line if (gradb != 0 && gradb != 1 && !(startWidth == 1 && endWidth == 1)) { accessor->moveTo(qFloor(xfb) + 1, y); if (selectionAccessor) selectionAccessor->moveTo(qFloor(xfb) + 1, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { qreal alpha = cs->opacityF(accessor->rawData()); opacity = b2b * c3.opacityF() + (1 - b2b) * alpha; col2.setOpacity(opacity); compositeOnePixel(accessor->rawData(), col2); } } // fill remaining pixels between current xfa,xfb if (!(startWidth == 1 && endWidth == 1)) { if (xfa < xfb) for (int i = qFloor(xfa) + 1; i <= qFloor(xfb); i++) { accessor->moveTo(i, y); if (selectionAccessor) selectionAccessor->moveTo(i, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), c3); } } else for (int i = qFloor(xfb); i <= qFloor(xfa) + 1; i++) { accessor->moveTo(i, y); if (selectionAccessor) selectionAccessor->moveTo(i, y); if (!selectionAccessor || *selectionAccessor->oldRawData() > SELECTION_THRESHOLD) { compositeOnePixel(accessor->rawData(), c3); } } } xfa += grada; xfb += gradb; } } } void KisPainter::setProgress(KoUpdater * progressUpdater) { d->progressUpdater = progressUpdater; } const KisPaintDeviceSP KisPainter::device() const { return d->device; } KisPaintDeviceSP KisPainter::device() { return d->device; } void KisPainter::setChannelFlags(QBitArray channelFlags) { // Q_ASSERT(channelFlags.isEmpty() || quint32(channelFlags.size()) == d->colorSpace->channelCount()); // Now, if all bits in the channelflags are true, pass an empty channel flags bitarray // because otherwise the compositeops cannot optimize. d->paramInfo.channelFlags = channelFlags; if (!channelFlags.isEmpty() && channelFlags == QBitArray(channelFlags.size(), true)) { d->paramInfo.channelFlags = QBitArray(); } } QBitArray KisPainter::channelFlags() { return d->paramInfo.channelFlags; } -void KisPainter::setPattern(const KoPattern * pattern) +void KisPainter::setPattern(const KoPatternSP pattern) { d->pattern = pattern; } -const KoPattern * KisPainter::pattern() const +const KoPatternSP KisPainter::pattern() const { return d->pattern; } void KisPainter::setPaintColor(const KoColor& color) { d->paintColor = color; if (d->device) { d->paintColor.convertTo(d->device->compositionSourceColorSpace()); } } const KoColor &KisPainter::paintColor() const { return d->paintColor; } void KisPainter::setBackgroundColor(const KoColor& color) { d->backgroundColor = color; if (d->device) { d->backgroundColor.convertTo(d->device->compositionSourceColorSpace()); } } const KoColor &KisPainter::backgroundColor() const { return d->backgroundColor; } void KisPainter::setGenerator(KisFilterConfigurationSP generator) { d->generator = generator; } const KisFilterConfigurationSP KisPainter::generator() const { return d->generator; } void KisPainter::setFillStyle(FillStyle fillStyle) { d->fillStyle = fillStyle; } KisPainter::FillStyle KisPainter::fillStyle() const { return d->fillStyle; } void KisPainter::setAntiAliasPolygonFill(bool antiAliasPolygonFill) { d->antiAliasPolygonFill = antiAliasPolygonFill; } bool KisPainter::antiAliasPolygonFill() { return d->antiAliasPolygonFill; } void KisPainter::setStrokeStyle(KisPainter::StrokeStyle strokeStyle) { d->strokeStyle = strokeStyle; } KisPainter::StrokeStyle KisPainter::strokeStyle() const { return d->strokeStyle; } void KisPainter::setFlow(quint8 flow) { d->paramInfo.flow = float(flow) / 255.0f; } quint8 KisPainter::flow() const { return quint8(d->paramInfo.flow * 255.0f); } void KisPainter::setOpacityUpdateAverage(quint8 opacity) { d->isOpacityUnit = opacity == OPACITY_OPAQUE_U8; d->paramInfo.updateOpacityAndAverage(float(opacity) / 255.0f); } void KisPainter::setAverageOpacity(qreal averageOpacity) { d->paramInfo.setOpacityAndAverage(d->paramInfo.opacity, averageOpacity); } qreal KisPainter::blendAverageOpacity(qreal opacity, qreal averageOpacity) { const float exponent = 0.1; return averageOpacity < opacity ? opacity : exponent * opacity + (1.0 - exponent) * (averageOpacity); } void KisPainter::setOpacity(quint8 opacity) { d->isOpacityUnit = opacity == OPACITY_OPAQUE_U8; d->paramInfo.opacity = float(opacity) / 255.0f; } quint8 KisPainter::opacity() const { return quint8(d->paramInfo.opacity * 255.0f); } void KisPainter::setCompositeOp(const KoCompositeOp * op) { d->compositeOp = op; } const KoCompositeOp * KisPainter::compositeOp() { return d->compositeOp; } /** * TODO: Rename this setCompositeOpId(). See KoCompositeOpRegistry.h */ void KisPainter::setCompositeOp(const QString& op) { d->compositeOp = d->colorSpace->compositeOp(op); } void KisPainter::setSelection(KisSelectionSP selection) { d->selection = selection; } KisSelectionSP KisPainter::selection() { return d->selection; } KoUpdater * KisPainter::progressUpdater() { return d->progressUpdater; } -void KisPainter::setGradient(const KoAbstractGradient* gradient) +void KisPainter::setGradient(const KoAbstractGradientSP gradient) { d->gradient = gradient; } -const KoAbstractGradient* KisPainter::gradient() const +const KoAbstractGradientSP KisPainter::gradient() const { return d->gradient; } void KisPainter::setPaintOpPreset(KisPaintOpPresetSP preset, KisNodeSP node, KisImageSP image) { d->paintOpPreset = preset; KisPaintOp *paintop = KisPaintOpRegistry::instance()->paintOp(preset, this, node, image); Q_ASSERT(paintop); if (paintop) { delete d->paintOp; d->paintOp = paintop; } else { warnKrita << "Could not create paintop for preset " << preset->name(); } } KisPaintOpPresetSP KisPainter::preset() const { return d->paintOpPreset; } KisPaintOp* KisPainter::paintOp() const { return d->paintOp; } void KisPainter::setMirrorInformation(const QPointF& axesCenter, bool mirrorHorizontally, bool mirrorVertically) { d->axesCenter = axesCenter; d->mirrorHorizontally = mirrorHorizontally; d->mirrorVertically = mirrorVertically; } void KisPainter::copyMirrorInformationFrom(const KisPainter *other) { d->axesCenter = other->d->axesCenter; d->mirrorHorizontally = other->d->mirrorHorizontally; d->mirrorVertically = other->d->mirrorVertically; } bool KisPainter::hasMirroring() const { return d->mirrorHorizontally || d->mirrorVertically; } bool KisPainter::hasHorizontalMirroring() const { return d->mirrorHorizontally; } bool KisPainter::hasVerticalMirroring() const { return d->mirrorVertically; } void KisPainter::setMaskImageSize(qint32 width, qint32 height) { d->maskImageWidth = qBound(1, width, 256); d->maskImageHeight = qBound(1, height, 256); d->fillPainter = 0; d->polygonMaskImage = QImage(); } //void KisPainter::setLockAlpha(bool protect) //{ // if(d->paramInfo.channelFlags.isEmpty()) { // d->paramInfo.channelFlags = d->colorSpace->channelFlags(true, true); // } // QBitArray switcher = // d->colorSpace->channelFlags(protect, !protect); // if(protect) { // d->paramInfo.channelFlags &= switcher; // } // else { // d->paramInfo.channelFlags |= switcher; // } // Q_ASSERT(quint32(d->paramInfo.channelFlags.size()) == d->colorSpace->channelCount()); //} //bool KisPainter::alphaLocked() const //{ // QBitArray switcher = d->colorSpace->channelFlags(false, true); // return !(d->paramInfo.channelFlags & switcher).count(true); //} void KisPainter::setRenderingIntent(KoColorConversionTransformation::Intent intent) { d->renderingIntent = intent; } void KisPainter::setColorConversionFlags(KoColorConversionTransformation::ConversionFlags conversionFlags) { d->conversionFlags = conversionFlags; } void KisPainter::setRunnableStrokeJobsInterface(KisRunnableStrokeJobsInterface *interface) { d->runnableStrokeJobsInterface = interface; } KisRunnableStrokeJobsInterface *KisPainter::runnableStrokeJobsInterface() const { if (!d->runnableStrokeJobsInterface) { if (!d->fakeRunnableStrokeJobsInterface) { d->fakeRunnableStrokeJobsInterface.reset(new KisFakeRunnableStrokeJobsExecutor()); } return d->fakeRunnableStrokeJobsInterface.data(); } return d->runnableStrokeJobsInterface; } void KisPainter::renderMirrorMaskSafe(QRect rc, KisFixedPaintDeviceSP dab, bool preserveDab) { if (!d->mirrorHorizontally && !d->mirrorVertically) return; KisFixedPaintDeviceSP dabToProcess = dab; if (preserveDab) { dabToProcess = new KisFixedPaintDevice(*dab); } renderMirrorMask(rc, dabToProcess); } void KisPainter::renderMirrorMaskSafe(QRect rc, KisPaintDeviceSP dab, int sx, int sy, KisFixedPaintDeviceSP mask, bool preserveMask) { if (!d->mirrorHorizontally && !d->mirrorVertically) return; KisFixedPaintDeviceSP maskToProcess = mask; if (preserveMask) { maskToProcess = new KisFixedPaintDevice(*mask); } renderMirrorMask(rc, dab, sx, sy, maskToProcess); } void KisPainter::renderMirrorMask(QRect rc, KisFixedPaintDeviceSP dab) { int x = rc.topLeft().x(); int y = rc.topLeft().y(); KisLodTransform t(d->device); QPoint effectiveAxesCenter = t.map(d->axesCenter).toPoint(); int mirrorX = -((x+rc.width()) - effectiveAxesCenter.x()) + effectiveAxesCenter.x(); int mirrorY = -((y+rc.height()) - effectiveAxesCenter.y()) + effectiveAxesCenter.y(); if (d->mirrorHorizontally && d->mirrorVertically){ dab->mirror(true, false); bltFixed(mirrorX, y, dab, 0,0,rc.width(),rc.height()); dab->mirror(false,true); bltFixed(mirrorX, mirrorY, dab, 0,0,rc.width(),rc.height()); dab->mirror(true, false); bltFixed(x, mirrorY, dab, 0,0,rc.width(),rc.height()); } else if (d->mirrorHorizontally){ dab->mirror(true, false); bltFixed(mirrorX, y, dab, 0,0,rc.width(),rc.height()); } else if (d->mirrorVertically){ dab->mirror(false, true); bltFixed(x, mirrorY, dab, 0,0,rc.width(),rc.height()); } } void KisPainter::renderMirrorMask(QRect rc, KisFixedPaintDeviceSP dab, KisFixedPaintDeviceSP mask) { int x = rc.topLeft().x(); int y = rc.topLeft().y(); KisLodTransform t(d->device); QPoint effectiveAxesCenter = t.map(d->axesCenter).toPoint(); int mirrorX = -((x+rc.width()) - effectiveAxesCenter.x()) + effectiveAxesCenter.x(); int mirrorY = -((y+rc.height()) - effectiveAxesCenter.y()) + effectiveAxesCenter.y(); if (d->mirrorHorizontally && d->mirrorVertically){ dab->mirror(true, false); mask->mirror(true, false); bltFixedWithFixedSelection(mirrorX,y, dab, mask, rc.width() ,rc.height() ); dab->mirror(false,true); mask->mirror(false, true); bltFixedWithFixedSelection(mirrorX,mirrorY, dab, mask, rc.width() ,rc.height() ); dab->mirror(true, false); mask->mirror(true, false); bltFixedWithFixedSelection(x,mirrorY, dab, mask, rc.width() ,rc.height() ); }else if (d->mirrorHorizontally){ dab->mirror(true, false); mask->mirror(true, false); bltFixedWithFixedSelection(mirrorX,y, dab, mask, rc.width() ,rc.height() ); }else if (d->mirrorVertically){ dab->mirror(false, true); mask->mirror(false, true); bltFixedWithFixedSelection(x,mirrorY, dab, mask, rc.width() ,rc.height() ); } } void KisPainter::renderMirrorMask(QRect rc, KisPaintDeviceSP dab){ if (d->mirrorHorizontally || d->mirrorVertically){ KisFixedPaintDeviceSP mirrorDab(new KisFixedPaintDevice(dab->colorSpace())); QRect dabRc( QPoint(0,0), QSize(rc.width(),rc.height()) ); mirrorDab->setRect(dabRc); mirrorDab->lazyGrowBufferWithoutInitialization(); dab->readBytes(mirrorDab->data(),rc); renderMirrorMask( QRect(rc.topLeft(),dabRc.size()), mirrorDab); } } void KisPainter::renderMirrorMask(QRect rc, KisPaintDeviceSP dab, int sx, int sy, KisFixedPaintDeviceSP mask) { if (d->mirrorHorizontally || d->mirrorVertically){ KisFixedPaintDeviceSP mirrorDab(new KisFixedPaintDevice(dab->colorSpace())); QRect dabRc( QPoint(0,0), QSize(rc.width(),rc.height()) ); mirrorDab->setRect(dabRc); mirrorDab->lazyGrowBufferWithoutInitialization(); dab->readBytes(mirrorDab->data(),QRect(QPoint(sx,sy),rc.size())); renderMirrorMask(rc, mirrorDab, mask); } } void KisPainter::renderDabWithMirroringNonIncremental(QRect rc, KisPaintDeviceSP dab) { QVector rects; int x = rc.topLeft().x(); int y = rc.topLeft().y(); KisLodTransform t(d->device); QPoint effectiveAxesCenter = t.map(d->axesCenter).toPoint(); int mirrorX = -((x+rc.width()) - effectiveAxesCenter.x()) + effectiveAxesCenter.x(); int mirrorY = -((y+rc.height()) - effectiveAxesCenter.y()) + effectiveAxesCenter.y(); rects << rc; if (d->mirrorHorizontally && d->mirrorVertically){ rects << QRect(mirrorX, y, rc.width(), rc.height()); rects << QRect(mirrorX, mirrorY, rc.width(), rc.height()); rects << QRect(x, mirrorY, rc.width(), rc.height()); } else if (d->mirrorHorizontally) { rects << QRect(mirrorX, y, rc.width(), rc.height()); } else if (d->mirrorVertically) { rects << QRect(x, mirrorY, rc.width(), rc.height()); } Q_FOREACH (const QRect &rc, rects) { d->device->clear(rc); } QRect resultRect = dab->extent() | rc; bool intersects = false; for (int i = 1; i < rects.size(); i++) { if (rects[i].intersects(resultRect)) { intersects = true; break; } } /** * If there are no cross-intersections, we can use a fast path * and do no cycling recompositioning */ if (!intersects) { rects.resize(1); } Q_FOREACH (const QRect &rc, rects) { bitBlt(rc.topLeft(), dab, rc); } Q_FOREACH (const QRect &rc, rects) { renderMirrorMask(rc, dab); } } bool KisPainter::hasDirtyRegion() const { return !d->dirtyRects.isEmpty(); } void KisPainter::mirrorRect(Qt::Orientation direction, QRect *rc) const { KisLodTransform t(d->device); QPoint effectiveAxesCenter = t.map(d->axesCenter).toPoint(); KritaUtils::mirrorRect(direction, effectiveAxesCenter, rc); } void KisPainter::mirrorDab(Qt::Orientation direction, KisRenderedDab *dab) const { KisLodTransform t(d->device); QPoint effectiveAxesCenter = t.map(d->axesCenter).toPoint(); KritaUtils::mirrorDab(direction, effectiveAxesCenter, dab); } const QVector KisPainter::calculateAllMirroredRects(const QRect &rc) { QVector rects; KisLodTransform t(d->device); QPoint effectiveAxesCenter = t.map(d->axesCenter).toPoint(); QRect baseRect = rc; rects << baseRect; if (d->mirrorHorizontally && d->mirrorVertically){ KritaUtils::mirrorRect(Qt::Horizontal, effectiveAxesCenter, &baseRect); rects << baseRect; KritaUtils::mirrorRect(Qt::Vertical, effectiveAxesCenter, &baseRect); rects << baseRect; KritaUtils::mirrorRect(Qt::Horizontal, effectiveAxesCenter, &baseRect); rects << baseRect; } else if (d->mirrorHorizontally) { KritaUtils::mirrorRect(Qt::Horizontal, effectiveAxesCenter, &baseRect); rects << baseRect; } else if (d->mirrorVertically) { KritaUtils::mirrorRect(Qt::Vertical, effectiveAxesCenter, &baseRect); rects << baseRect; } return rects; } diff --git a/libs/image/kis_painter.h b/libs/image/kis_painter.h index 46c02ccf7c..97764594d8 100644 --- a/libs/image/kis_painter.h +++ b/libs/image/kis_painter.h @@ -1,879 +1,880 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004 Clarence Dang * Copyright (c) 2008-2010 Lukáš Tvrdý * Copyright (c) 2010 José Luis Vergara Toloza * * 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_PAINTER_H_ #define KIS_PAINTER_H_ #include #include #include #include +#include +#include #include "kundo2magicstring.h" #include "kis_types.h" #include #include + class QPen; class KUndo2Command; class QRect; class QRectF; class QBitArray; class QPainterPath; -class KoAbstractGradient; class KoUpdater; class KoColor; class KoCompositeOp; class KisUndoAdapter; class KisPostExecutionUndoAdapter; class KisTransaction; -class KoPattern; class KisPaintInformation; class KisPaintOp; class KisDistanceInformation; struct KisRenderedDab; class KisRunnableStrokeJobsInterface; /** * KisPainter contains the graphics primitives necessary to draw on a * KisPaintDevice. This is the same kind of abstraction as used in Qt * itself, where you have QPainter and QPaintDevice. * * However, KisPainter works on a tiled image and supports different * color models, and that's a lot more complicated. * * KisPainter supports transactions that can group various paint operations * in one undoable step. * * For more complex operations, you might want to have a look at the subclasses * of KisPainter: KisConvolutionPainter, KisFillPainter and KisGradientPainter * * KisPainter sets a number of default values, like COMPOSITE_OVER for compositeop, * OPACITY_OPAQUE for opacity and no selection for selection. */ class KRITAIMAGE_EXPORT KisPainter { public: /// Construct painter without a device KisPainter(); /// Construct a painter, and begin painting on the device KisPainter(KisPaintDeviceSP device); /// Construct a painter, and begin painting on the device. All actions will be masked by the given selection. KisPainter(KisPaintDeviceSP device, KisSelectionSP selection); virtual ~KisPainter(); public: static void copyAreaOptimized(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &originalSrcRect); static void copyAreaOptimizedOldData(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &originalSrcRect); static void copyAreaOptimized(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &originalSrcRect, KisSelectionSP selection); static KisPaintDeviceSP convertToAlphaAsAlpha(KisPaintDeviceSP src); static KisPaintDeviceSP convertToAlphaAsGray(KisPaintDeviceSP src); static bool checkDeviceHasTransparency(KisPaintDeviceSP dev); /** * Start painting on the specified device. Not undoable. */ void begin(KisPaintDeviceSP device); /** * Start painting on the specified paint device. All actions will be masked by the given selection. */ void begin(KisPaintDeviceSP device, KisSelectionSP selection); /** * Finish painting on the current device */ void end(); /** * If set, the painter action is cancelable, if the action supports that. */ void setProgress(KoUpdater * progressUpdater); /// Begin an undoable paint operation void beginTransaction(const KUndo2MagicString& transactionName = KUndo2MagicString(),int timedID = -1); /// Cancel all the changes made by the painter void revertTransaction(); /// Finish the undoable paint operation void endTransaction(KisUndoAdapter *undoAdapter); /** * Finish transaction and load it to a special adapter for strokes */ void endTransaction(KisPostExecutionUndoAdapter *undoAdapter); /** * Finishes a transaction and returns a pointer to its undo command */ KUndo2Command* endAndTakeTransaction(); /** * Finish the transaction and delete it's undo information. * NOTE: Be careful, because all the previous transactions * will become non-undoable after execution of this method. */ void deleteTransaction(); /// continue a transaction started somewhere else void putTransaction(KisTransaction* transaction); /// take transaction out of the reach of KisPainter KisTransaction* takeTransaction(); /// Returns the current paint device. const KisPaintDeviceSP device() const; KisPaintDeviceSP device(); /** * Blast a region of srcWidth @param srcWidth and srcHeight @param srcHeight from @param * srcDev onto the current paint device. @param srcX and @param srcY set the x and y * positions of the origin top-left corner, @param dstX and @param dstY those of * the destination. * Any pixel read outside the limits of @param srcDev will return the * default pixel, this is a property of \ref KisPaintDevice. * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param srcX the source x-coordinate * @param srcY the source y-coordinate * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated */ void bitBlt(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight); /** * Convenience method that uses QPoint and QRect. * * @param pos the destination coordinate, it replaces @param dstX and @param dstY. * @param srcDev the source device. * @param srcRect the rectangle describing the area to blast from @param srcDev into the current paint device. * @param srcRect replaces @param srcX, @param srcY, @param srcWidth and @param srcHeight. * */ void bitBlt(const QPoint & pos, const KisPaintDeviceSP srcDev, const QRect & srcRect); /** * The same as @ref bitBlt() but reads data from oldData() part of the device * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param srcX the source x-coordinate * @param srcY the source y-coordinate * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated */ void bitBltOldData(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight); /** * Convenience method that uses QPoint and QRect. * * @param pos the destination coordinate, it replaces @param dstX and @param dstY. * @param srcDev the source device. * @param srcRect the rectangle describing the area to blast from @param srcDev into the current paint device. * @param srcRect replaces @param srcX, @param srcY, @param srcWidth and @param srcHeight. * */ void bitBltOldData(const QPoint & pos, const KisPaintDeviceSP srcDev, const QRect & srcRect); /** * Blasts a @param selection of srcWidth @param srcWidth and srcHeight @param srcHeight * of @param srcDev on the current paint device. There is parameters * to control where the area begins in each distinct device, explained below. * @param selection can be used as a mask to shape @param srcDev to * something interesting in the same step it is rendered to the current * paint device. @param selection 's colorspace must be alpha8 (the * colorspace for selections/transparency), the rectangle formed by * @param selX, @param selY, @param srcWidth and @param srcHeight must not go * beyond its limits, and they must be different from zero. * @param selection and KisPainter's selection (the user selection) are * fused together through the composite operation COMPOSITE_MULT. * Any pixel read outside the limits of @param srcDev will return the * default pixel, this is a property of \ref KisPaintDevice. * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param selection the custom selection to apply on the source device * @param selX the selection x-coordinate * @param selY the selection y-coordinate * @param srcX the source x-coordinate * @param srcY the source y-coordinate * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated * */ void bitBltWithFixedSelection(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, qint32 selX, qint32 selY, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight); /** * Convenience method that assumes @param selX, @param selY, @param srcX and @param srcY are * equal to 0. Best used when @param selection and the desired area of @param srcDev have exactly * the same dimensions and are specially made for each other. * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param selection the custom selection to apply on the source device * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated */ void bitBltWithFixedSelection(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, qint32 srcWidth, qint32 srcHeight); /** * Blast a region of srcWidth @param srcWidth and srcHeight @param srcHeight from @param srcDev onto the current * paint device. @param srcX and @param srcY set the x and y positions of the * origin top-left corner, @param dstX and @param dstY those of the destination. * @param srcDev is a \ref KisFixedPaintDevice: this means that @param srcDev must have the same * colorspace as the destination device. * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param srcX the source x-coordinate * @param srcY the source y-coordinate * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated */ void bltFixed(qint32 dstX, qint32 dstY, const KisFixedPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight); /** * Render the area \p rc from \p srcDevices on the destination device. * If \p rc doesn't cross the device's rect, then the device is not * rendered at all. */ void bltFixed(const QRect &rc, const QList allSrcDevices); /** * Convenience method that uses QPoint and QRect. * * @param pos the destination coordinate, it replaces @param dstX and @param dstY. * @param srcDev the source device. * @param srcRect the rectangle describing the area to blast from @param srcDev into the current paint device. * @param srcRect replaces @param srcX, @param srcY, @param srcWidth and @param srcHeight. * */ void bltFixed(const QPoint & pos, const KisFixedPaintDeviceSP srcDev, const QRect & srcRect); /** * Blasts a @param selection of srcWidth @param srcWidth and srcHeight @param srcHeight * of @param srcDev on the current paint device. There is parameters to control * the top-left corner of the area in each respective paint device (@param dstX, * @param dstY, @param srcX, @param srcY). * @param selection can be used as a mask to shape @param srcDev to something * interesting in the same step it is rendered to the current paint device. * @param srcDev is a \ref KisFixedPaintDevice: this means that @param srcDev * must have the same colorspace as the destination device. * @param selection 's colorspace must be alpha8 (the colorspace for * selections/transparency). * The rectangle formed by the respective top-left coordinates of each device * and @param srcWidth and @param srcHeight must not go beyond their limits, and * they must be different from zero. * @param selection and KisPainter's selection (the user selection) are * fused together through the composite operation COMPOSITE_MULT. * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param selection the selection stored in fixed device * @param selX the selection x-coordinate * @param selY the selection y-coordinate * @param srcX the source x-coordinate * @param srcY the source y-coordinate * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated */ void bltFixedWithFixedSelection(qint32 dstX, qint32 dstY, const KisFixedPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, qint32 selX, qint32 selY, qint32 srcX, qint32 srcY, quint32 srcWidth, quint32 srcHeight); /** * Convenience method that assumes @param selX, @param selY, @param srcX and @param srcY are * equal to 0. Best used when @param selection and @param srcDev have exactly the same * dimensions and are specially made for each other. * * @param dstX the destination x-coordinate * @param dstY the destination y-coordinate * @param srcDev the source device * @param selection the custom selection to apply on the source device * @param srcWidth the width of the region to be manipulated * @param srcHeight the height of the region to be manipulated */ void bltFixedWithFixedSelection(qint32 dstX, qint32 dstY, const KisFixedPaintDeviceSP srcDev, const KisFixedPaintDeviceSP selection, quint32 srcWidth, quint32 srcHeight); /** * fills a region of width @param width and height @param height of the current * paint device with the color @param color. @param x and @param y set the x and y positions of the * origin top-left corner. * * @param x the destination x-coordinate * @param y the destination y-coordinate * @param width the width of the region to be manipulated * @param height the height of the region to be manipulated * @param color the color the area is filled with */ void fill(qint32 x, qint32 y, qint32 width, qint32 height, const KoColor& color); /** * First you need to setup the painter with setMirrorInformation, * then these set of methods provide way to render the devices mirrored * according the axesCenter vertically or horizontally or both. * * @param rc rectangle area covered by dab * @param dab this device will be mirrored in-place, it means that it will be changed */ void renderMirrorMask(QRect rc, KisFixedPaintDeviceSP dab); void renderMirrorMask(QRect rc, KisFixedPaintDeviceSP dab, KisFixedPaintDeviceSP mask); void renderMirrorMask(QRect rc, KisPaintDeviceSP dab); void renderMirrorMask(QRect rc, KisPaintDeviceSP dab, int sx, int sy, KisFixedPaintDeviceSP mask); /** * Convenience method for renderMirrorMask(), allows to choose whether * we need to preserve out dab or do the transformations in-place. * * @param rc rectangle area covered by dab * @param dab the device to render * @param preserveDab states whether a temporary device should be * created to do the transformations */ void renderMirrorMaskSafe(QRect rc, KisFixedPaintDeviceSP dab, bool preserveDab); /** * Convenience method for renderMirrorMask(), allows to choose whether * we need to preserve our fixed mask or do the transformations in-place. * * @param rc rectangle area covered by dab * @param dab the device to render * @param mask mask to use for rendering * @param preserveMask states whether a temporary device should be * created to do the transformations */ void renderMirrorMaskSafe(QRect rc, KisPaintDeviceSP dab, int sx, int sy, KisFixedPaintDeviceSP mask, bool preserveMask); /** * A complex method that re-renders a dab on an \p rc area. * The \p rc area and all the dedicated mirroring areas are cleared * before the painting, so this method should be used by paintops * which do not update the canvas incrementally, but instead * regenerate some internal cache \p dab with the COMPOSITE_COPY op. * * \see KisExperimentPaintOp */ void renderDabWithMirroringNonIncremental(QRect rc, KisPaintDeviceSP dab); /** * @return true if the painter has some rects marked as dirty * @see takeDirtyRegion(), addDirtyRect() */ bool hasDirtyRegion() const; /** * The methods in this class do not tell the paintdevice to update, but they calculate the * dirty area. This method returns this dirty area and resets it. */ QVector takeDirtyRegion(); /** * Paint a line that connects the dots in points */ void paintPolyline(const QVector &points, int index = 0, int numPoints = -1); /** * Draw a line between pos1 and pos2 using the currently set brush and color. * If savedDist is less than zero, the brush is painted at pos1 before being * painted along the line using the spacing setting. * @return the drag distance, that is the remains of the distance between p1 and p2 not covered * because the currently set brush has a spacing greater than that distance. */ void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance); /** * Draw a Bezier curve between pos1 and pos2 using control points 1 and 2. * If savedDist is less than zero, the brush is painted at pos1 before being * painted along the curve using the spacing setting. * @return the drag distance, that is the remains of the distance between p1 and p2 not covered * because the currently set brush has a spacing greater than that distance. */ void paintBezierCurve(const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2, KisDistanceInformation *currentDistance); /** * Fill the given vector points with the points needed to draw the Bezier curve between * pos1 and pos2 using control points 1 and 2, excluding the final pos2. */ void getBezierCurvePoints(const QPointF &pos1, const QPointF &control1, const QPointF &control2, const QPointF &pos2, vQPointF& points) const; /** * Paint a rectangle. * @param rect the rectangle to paint. */ void paintRect(const QRectF &rect); /** * Paint a rectangle. * * @param x x coordinate of the top-left corner * @param y y coordinate of the top-left corner * @param w the rectangle width * @param h the rectangle height */ void paintRect(const qreal x, const qreal y, const qreal w, const qreal h); /** * Paint the ellipse that fills the given rectangle. * * @param rect the rectangle containing the ellipse to paint. */ void paintEllipse(const QRectF &rect); /** * Paint the ellipse that fills the given rectangle. * * @param x x coordinate of the top-left corner * @param y y coordinate of the top-left corner * @param w the rectangle width * @param h the rectangle height */ void paintEllipse(const qreal x, const qreal y, const qreal w, const qreal h); /** * Paint the polygon with the points given in points. It automatically closes the polygon * by drawing the line from the last point to the first. */ void paintPolygon(const vQPointF& points); /** Draw a spot at pos using the currently set paint op, brush and color */ void paintAt(const KisPaintInformation &pos, KisDistanceInformation *savedDist); /** * Stroke the given QPainterPath. */ void paintPainterPath(const QPainterPath& path); /** * Fills the area enclosed by the given QPainterPath * Convenience method for fillPainterPath(path, rect) */ void fillPainterPath(const QPainterPath& path); /** * Fills the portion of an area enclosed by the given QPainterPath * * \param rect the portion of the path to fill */ void fillPainterPath(const QPainterPath& path, const QRect &requestedRect); /** * Draw the path using the Pen * * if \p requestedRect is null, the entire path is painted */ void drawPainterPath(const QPainterPath& path, const QPen& pen, const QRect &requestedRect); // convenience overload void drawPainterPath(const QPainterPath& path, const QPen& pen); /** * paint an unstroked one-pixel wide line from specified start position to the * specified end position. * */ void drawLine(const QPointF & start, const QPointF & end); /** * paint an unstroked line with thickness from specified start position to the * specified end position. Scanline algorithm is used. */ void drawLine(const QPointF &start, const QPointF &end, qreal width, bool antialias); /** * paints an unstroked, aliased one-pixel line using the DDA algorithm from specified start position to the * specified end position. * */ void drawDDALine(const QPointF & start, const QPointF & end); /** * Paint an unstroked, wobbly one-pixel wide line from the specified start to the specified * end position. * */ void drawWobblyLine(const QPointF & start, const QPointF & end); /** * Paint an unstroked, anti-aliased one-pixel wide line from the specified start to the specified * end position using the Wu algorithm */ void drawWuLine(const QPointF & start, const QPointF & end); /** * Paint an unstroked wide line from the specified start to the specified * end position with width varying from @param w1 at the start to @param w2 at * the end. * * XXX: the width should be set in doubles, not integers. */ void drawThickLine(const QPointF & start, const QPointF & end, int startWidth, int endWidth); /** * Set the channelflags: a bit array where true means that the * channel corresponding in position with the bit will be read * by the operation, and false means that it will not be affected. * * An empty channelFlags parameter means that all channels are * affected. * * @param the bit array that masks the source channels; only * the channels where the corresponding bit is true will will be * composited onto the destination device. */ void setChannelFlags(QBitArray channelFlags); /// @return the channel flags QBitArray channelFlags(); /** * Set the paintop preset to use. If @param image is given, * the paintop will be created using this image as parameter. * Some paintops really want to know about the image they work * for, e.g. the clone paintop. */ void setPaintOpPreset(KisPaintOpPresetSP preset, KisNodeSP node, KisImageSP image); /// Return the paintop preset KisPaintOpPresetSP preset() const; /** * Return the active paintop (which is created based on the specified preset and * will be deleted as soon as the KisPainter instance dies). */ KisPaintOp* paintOp() const; void setMirrorInformation(const QPointF &axesCenter, bool mirrorHorizontally, bool mirrorVertically); void copyMirrorInformationFrom(const KisPainter *other); /** * Returns whether the mirroring methods will do any * work when called */ bool hasMirroring() const; /** * Indicates if horizontal mirroring mode is activated */ bool hasHorizontalMirroring() const; /** * Indicates if vertical mirroring mode is activated */ bool hasVerticalMirroring() const; /** * Mirror \p rc in the requested \p direction around the center point defined * in the painter. */ void mirrorRect(Qt::Orientation direction, QRect *rc) const; /** * Mirror \p dab in the requested direction around the center point defined * in the painter. The dab's offset is adjusted automatically. */ void mirrorDab(Qt::Orientation direction, KisRenderedDab *dab) const; /** * Calculate the list of the mirrored rects that will be painted on the * the canvas when calling renderMirrorMask() at al */ const QVector calculateAllMirroredRects(const QRect &rc); /// Set the current pattern - void setPattern(const KoPattern * pattern); + void setPattern(const KoPatternSP pattern); /// Returns the currently set pattern - const KoPattern * pattern() const; + const KoPatternSP pattern() const; /** * Set the color that will be used to paint with, and convert it * to the color space of the current paint device. */ void setPaintColor(const KoColor& color); /// Returns the color that will be used to paint with const KoColor &paintColor() const; /** * Set the current background color, and convert it * to the color space of the current paint device. */ void setBackgroundColor(const KoColor& color); /// Returns the current background color const KoColor &backgroundColor() const; /// Set the current generator (a generator can be used to fill an area void setGenerator(KisFilterConfigurationSP generator); /// @return the current generator configuration const KisFilterConfigurationSP generator() const; /// This enum contains the styles with which we can fill things like polygons and ellipses enum FillStyle { FillStyleNone, FillStyleForegroundColor, FillStyleBackgroundColor, FillStylePattern, FillStyleGradient, FillStyleStrokes, FillStyleGenerator, }; /// Set the current style with which to fill void setFillStyle(FillStyle fillStyle); /// Returns the current fill style FillStyle fillStyle() const; /// Set whether a polygon's filled area should be anti-aliased or not. The default is true. void setAntiAliasPolygonFill(bool antiAliasPolygonFill); /// Return whether a polygon's filled area should be anti-aliased or not bool antiAliasPolygonFill(); /// The style of the brush stroke around polygons and so enum StrokeStyle { StrokeStyleNone, StrokeStyleBrush }; /// Set the current brush stroke style void setStrokeStyle(StrokeStyle strokeStyle); /// Returns the current brush stroke style StrokeStyle strokeStyle() const; void setFlow(quint8 flow); quint8 flow() const; /** * Sets the opacity of the painting and recalculates the * mean opacity of the stroke. This mean value is used to * make ALPHA_DARKEN painting look correct */ void setOpacityUpdateAverage(quint8 opacity); /** * Sets average opacity, that is used to make ALPHA_DARKEN painting look correct */ void setAverageOpacity(qreal averageOpacity); /** * Calculate average opacity value after painting a single dab with \p opacity */ static qreal blendAverageOpacity(qreal opacity, qreal averageOpacity); /// Set the opacity which is used in painting (like filling polygons) void setOpacity(quint8 opacity); /// Returns the opacity that is used in painting quint8 opacity() const; /// Set the composite op for this painter void setCompositeOp(const KoCompositeOp * op); const KoCompositeOp * compositeOp(); /// Set the composite op for this painter by string. /// Note: the colorspace must be set previously! void setCompositeOp(const QString& op); /** * Add \p r to the current set of dirty rects */ void addDirtyRect(const QRect &r); /** * Add \p rects to the current set of dirty rects */ void addDirtyRects(const QVector &rects); /** * Reset the selection to the given selection. All painter actions will be * masked by the specified selection. */ void setSelection(KisSelectionSP selection); /** * @return the selection set on this painter. */ KisSelectionSP selection(); - void setGradient(const KoAbstractGradient* gradient); - const KoAbstractGradient* gradient() const; + void setGradient(const KoAbstractGradientSP gradient); + const KoAbstractGradientSP gradient() const; /** * Set the size of the tile in fillPainterPath, useful when optimizing the use of fillPainterPath * e.g. Spray paintop uses more small tiles, although selections uses bigger tiles. QImage::fill * is quite expensive so with smaller images you can save instructions * Default and maximum size is 256x256 image */ void setMaskImageSize(qint32 width, qint32 height); // /** // * If the alpha channel is locked, the alpha values of the paint device we are painting on // * will not change. // */ // void setLockAlpha(bool protect); // bool alphaLocked() const; /** * set the rendering intent in case pixels need to be converted before painting */ void setRenderingIntent(KoColorConversionTransformation::Intent intent); /** * set the conversion flags in case pixels need to be converted before painting */ void setColorConversionFlags(KoColorConversionTransformation::ConversionFlags conversionFlags); /** * Set interface for running asynchronous jobs by paintops. * * NOTE: the painter does *not* own the interface device. It is the responsibility * of the caller to ensure that the interface object is alive during the lifetime * of the painter. */ void setRunnableStrokeJobsInterface(KisRunnableStrokeJobsInterface *interface); /** * Get the interface for running asynchronous jobs. It is used by paintops mostly. */ KisRunnableStrokeJobsInterface* runnableStrokeJobsInterface() const; protected: /// Initialize, set everything to '0' or defaults void init(); /// Fill the polygon defined by points with the fillStyle void fillPolygon(const vQPointF& points, FillStyle fillStyle); private: KisPainter(const KisPainter&); KisPainter& operator=(const KisPainter&); float frac(float value) { float tmp = 0; return modff(value , &tmp); } float invertFrac(float value) { float tmp = 0; return 1.0f - modff(value , &tmp); } protected: KoUpdater * progressUpdater(); private: template void bitBltImpl(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight); inline void compositeOnePixel(quint8 *dst, const KoColor &color); private: struct Private; Private* const d; }; #endif // KIS_PAINTER_H_ diff --git a/libs/image/kis_painter_p.h b/libs/image/kis_painter_p.h index fd150fdb5e..fc1f9884a9 100644 --- a/libs/image/kis_painter_p.h +++ b/libs/image/kis_painter_p.h @@ -1,105 +1,105 @@ /* * Copyright (c) 2017 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. */ #ifndef KISPAINTERPRIVATE_H #define KISPAINTERPRIVATE_H #include #include #include #include #include "kis_paintop.h" #include "kis_selection.h" #include "kis_fill_painter.h" #include "kis_painter.h" #include "kis_paintop_preset.h" #include struct Q_DECL_HIDDEN KisPainter::Private { Private(KisPainter *_q) : q(_q) {} Private(KisPainter *_q, const KoColorSpace *cs) : q(_q), paintColor(cs), backgroundColor(cs) {} KisPainter *q; KisPaintDeviceSP device; KisSelectionSP selection; KisTransaction* transaction; KoUpdater* progressUpdater; QVector dirtyRects; KisPaintOp* paintOp; KoColor paintColor; KoColor backgroundColor; KoColor customColor; KisFilterConfigurationSP generator; KisPaintLayer* sourceLayer; FillStyle fillStyle; StrokeStyle strokeStyle; bool antiAliasPolygonFill; - const KoPattern* pattern; + KoPatternSP pattern; QPointF duplicateOffset; quint32 pixelSize; const KoColorSpace* colorSpace; KoColorProfile* profile; const KoCompositeOp* compositeOp; - const KoAbstractGradient* gradient; + KoAbstractGradientSP gradient; KisPaintOpPresetSP paintOpPreset; QImage polygonMaskImage; QPainter* maskPainter; KisFillPainter* fillPainter; KisPaintDeviceSP polygon; qint32 maskImageWidth; qint32 maskImageHeight; QPointF axesCenter; bool mirrorHorizontally; bool mirrorVertically; bool isOpacityUnit; // TODO: move into ParameterInfo KoCompositeOp::ParameterInfo paramInfo; KoColorConversionTransformation::Intent renderingIntent; KoColorConversionTransformation::ConversionFlags conversionFlags; KisRunnableStrokeJobsInterface *runnableStrokeJobsInterface = 0; QScopedPointer fakeRunnableStrokeJobsInterface; bool tryReduceSourceRect(const KisPaintDevice *srcDev, QRect *srcRect, qint32 *srcX, qint32 *srcY, qint32 *srcWidth, qint32 *srcHeight, qint32 *dstX, qint32 *dstY); void fillPainterPathImpl(const QPainterPath& path, const QRect &requestedRect); void applyDevice(const QRect &applyRect, const KisRenderedDab &dab, KisRandomAccessorSP dstIt, const KoColorSpace *srcColorSpace, KoCompositeOp::ParameterInfo &localParamInfo); void applyDeviceWithSelection(const QRect &applyRect, const KisRenderedDab &dab, KisRandomAccessorSP dstIt, KisRandomConstAccessorSP maskIt, const KoColorSpace *srcColorSpace, KoCompositeOp::ParameterInfo &localParamInfo); }; #endif // KISPAINTERPRIVATE_H diff --git a/libs/image/kis_types.h b/libs/image/kis_types.h index 87793d8db0..19aeb25eb2 100644 --- a/libs/image/kis_types.h +++ b/libs/image/kis_types.h @@ -1,310 +1,310 @@ /* * Copyright (c) 2002 Patrick Julien * * 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 KISTYPES_H_ #define KISTYPES_H_ #include #include #include #include "kritaimage_export.h" template class KisWeakSharedPtr; template class KisSharedPtr; template class QSharedPointer; template class QWeakPointer; template uint qHash(KisSharedPtr ptr) { return qHash(ptr.data()); } template uint qHash(KisWeakSharedPtr ptr) { return qHash(ptr.data()); } /** * Define lots of shared pointer versions of Krita classes. * Shared pointer classes have the advantage of near automatic * memory management (but beware of circular references) * These types should never be passed by reference, * because that will mess up their reference counter. * * An example of the naming pattern used: * * KisPaintDeviceSP is a KisSharedPtr of KisPaintDevice * KisPaintDeviceWSP is a KisWeakSharedPtr of KisPaintDevice * vKisPaintDeviceSP is a QVector of KisPaintDeviceSP * vKisPaintDeviceSP_it is an iterator of vKisPaintDeviceSP * */ class KisImage; typedef KisSharedPtr KisImageSP; typedef KisWeakSharedPtr KisImageWSP; class KisPaintDevice; typedef KisSharedPtr KisPaintDeviceSP; typedef KisWeakSharedPtr KisPaintDeviceWSP; typedef QVector vKisPaintDeviceSP; typedef vKisPaintDeviceSP::iterator vKisPaintDeviceSP_it; class KisFixedPaintDevice; typedef KisSharedPtr KisFixedPaintDeviceSP; class KisMask; typedef KisSharedPtr KisMaskSP; typedef KisWeakSharedPtr KisMaskWSP; class KisNode; typedef KisSharedPtr KisNodeSP; typedef KisWeakSharedPtr KisNodeWSP; typedef QVector vKisNodeSP; typedef vKisNodeSP::iterator vKisNodeSP_it; typedef vKisNodeSP::const_iterator vKisNodeSP_cit; class KisBaseNode; typedef KisSharedPtr KisBaseNodeSP; typedef KisWeakSharedPtr KisBaseNodeWSP; class KisEffectMask; typedef KisSharedPtr KisEffectMaskSP; typedef KisWeakSharedPtr KisEffectMaskWSP; class KisFilterMask; typedef KisSharedPtr KisFilterMaskSP; typedef KisWeakSharedPtr KisFilterMaskWSP; class KisTransformMask; typedef KisSharedPtr KisTransformMaskSP; typedef KisWeakSharedPtr KisTransformMaskWSP; class KisTransformMaskParamsInterface; typedef QSharedPointer KisTransformMaskParamsInterfaceSP; typedef QWeakPointer KisTransformMaskParamsInterfaceWSP; class KisTransparencyMask; typedef KisSharedPtr KisTransparencyMaskSP; typedef KisWeakSharedPtr KisTransparencyMaskWSP; class KisColorizeMask; typedef KisSharedPtr KisColorizeMaskSP; typedef KisWeakSharedPtr KisColorizeMaskWSP; class KisLayer; typedef KisSharedPtr KisLayerSP; typedef KisWeakSharedPtr KisLayerWSP; class KisShapeLayer; typedef KisSharedPtr KisShapeLayerSP; class KisPaintLayer; typedef KisSharedPtr KisPaintLayerSP; class KisAdjustmentLayer; typedef KisSharedPtr KisAdjustmentLayerSP; class KisGeneratorLayer; typedef KisSharedPtr KisGeneratorLayerSP; class KisCloneLayer; typedef KisSharedPtr KisCloneLayerSP; typedef KisWeakSharedPtr KisCloneLayerWSP; class KisGroupLayer; typedef KisSharedPtr KisGroupLayerSP; typedef KisWeakSharedPtr KisGroupLayerWSP; class KisFileLayer; typedef KisSharedPtr KisFileLayerSP; typedef KisWeakSharedPtr KisFileLayerWSP; class KisSelection; typedef KisSharedPtr KisSelectionSP; typedef KisWeakSharedPtr KisSelectionWSP; class KisSelectionComponent; typedef KisSharedPtr KisSelectionComponentSP; class KisSelectionMask; typedef KisSharedPtr KisSelectionMaskSP; class KisPixelSelection; typedef KisSharedPtr KisPixelSelectionSP; class KisHistogram; typedef KisSharedPtr KisHistogramSP; typedef QVector vKisSegments; class KisFilter; typedef KisSharedPtr KisFilterSP; class KisLayerStyleFilter; typedef KisSharedPtr KisLayerStyleFilterSP; class KisGenerator; typedef KisSharedPtr KisGeneratorSP; class KisConvolutionKernel; typedef KisSharedPtr KisConvolutionKernelSP; class KisAnnotation; typedef KisSharedPtr KisAnnotationSP; typedef QVector vKisAnnotationSP; typedef vKisAnnotationSP::iterator vKisAnnotationSP_it; typedef vKisAnnotationSP::const_iterator vKisAnnotationSP_cit; class KisAnimationFrameCache; typedef KisSharedPtr KisAnimationFrameCacheSP; typedef KisWeakSharedPtr KisAnimationFrameCacheWSP; class KisPaintingAssistant; typedef QSharedPointer KisPaintingAssistantSP; typedef QWeakPointer KisPaintingAssistantWSP; class KisReferenceImage; typedef QSharedPointer KisReferenceImageSP; typedef QWeakPointer KisReferenceImageWSP; // Repeat iterators class KisHLineIterator2; template class KisRepeatHLineIteratorPixelBase; typedef KisRepeatHLineIteratorPixelBase< KisHLineIterator2 > KisRepeatHLineConstIteratorNG; typedef KisSharedPtr KisRepeatHLineConstIteratorSP; class KisVLineIterator2; template class KisRepeatVLineIteratorPixelBase; typedef KisRepeatVLineIteratorPixelBase< KisVLineIterator2 > KisRepeatVLineConstIteratorNG; typedef KisSharedPtr KisRepeatVLineConstIteratorSP; // NG Iterators class KisHLineIteratorNG; typedef KisSharedPtr KisHLineIteratorSP; class KisHLineConstIteratorNG; typedef KisSharedPtr KisHLineConstIteratorSP; class KisVLineIteratorNG; typedef KisSharedPtr KisVLineIteratorSP; class KisVLineConstIteratorNG; typedef KisSharedPtr KisVLineConstIteratorSP; class KisRandomConstAccessorNG; typedef KisSharedPtr KisRandomConstAccessorSP; class KisRandomAccessorNG; typedef KisSharedPtr KisRandomAccessorSP; class KisRandomSubAccessor; typedef KisSharedPtr KisRandomSubAccessorSP; // Things typedef QVector vQPointF; class KisPaintOpPreset; -typedef KisSharedPtr KisPaintOpPresetSP; -typedef KisWeakSharedPtr KisPaintOpPresetWSP; +typedef QSharedPointer KisPaintOpPresetSP; +typedef QWeakPointer KisPaintOpPresetWSP; template class KisPinnedSharedPtr; class KisPaintOpSettings; typedef KisPinnedSharedPtr KisPaintOpSettingsSP; template class KisRestrictedSharedPtr; typedef KisRestrictedSharedPtr KisPaintOpSettingsRestrictedSP; class KisPaintOp; typedef KisSharedPtr KisPaintOpSP; class KoID; typedef QList KoIDList; class KoUpdater; template class QPointer; typedef QPointer KoUpdaterPtr; class KisProcessingVisitor; typedef KisSharedPtr KisProcessingVisitorSP; class KUndo2Command; typedef QSharedPointer KUndo2CommandSP; typedef QList KisNodeList; typedef QSharedPointer KisNodeListSP; typedef QList KisPaintDeviceList; class KisStroke; typedef QSharedPointer KisStrokeSP; typedef QWeakPointer KisStrokeWSP; typedef KisStrokeWSP KisStrokeId; class KisFilterConfiguration; typedef KisPinnedSharedPtr KisFilterConfigurationSP; class KisPropertiesConfiguration; typedef KisPinnedSharedPtr KisPropertiesConfigurationSP; class KisLockedProperties; typedef KisSharedPtr KisLockedPropertiesSP; class KisProjectionUpdatesFilter; typedef QSharedPointer KisProjectionUpdatesFilterSP; class KisAbstractProjectionPlane; typedef QSharedPointer KisAbstractProjectionPlaneSP; typedef QWeakPointer KisAbstractProjectionPlaneWSP; class KisProjectionLeaf; typedef QSharedPointer KisProjectionLeafSP; typedef QWeakPointer KisProjectionLeafWSP; class KisKeyframe; typedef QSharedPointer KisKeyframeSP; typedef QWeakPointer KisKeyframeWSP; class KisFilterChain; typedef KisSharedPtr KisFilterChainSP; class KisProofingConfiguration; typedef QSharedPointer KisProofingConfigurationSP; typedef QWeakPointer KisProofingConfigurationWSP; class KisLayerComposition; typedef QSharedPointer KisLayerCompositionSP; typedef QWeakPointer KisLayerCompositionWSP; #include #include #include #include #include #endif // KISTYPES_H_ diff --git a/libs/image/layerstyles/kis_ls_utils.cpp b/libs/image/layerstyles/kis_ls_utils.cpp index b60a462d62..72b9691ef2 100644 --- a/libs/image/layerstyles/kis_ls_utils.cpp +++ b/libs/image/layerstyles/kis_ls_utils.cpp @@ -1,586 +1,586 @@ /* * 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_ls_utils.h" #include #include #include #include "psd.h" #include "kis_default_bounds.h" #include "kis_pixel_selection.h" #include "kis_random_accessor_ng.h" #include "kis_iterator_ng.h" #include "kis_convolution_kernel.h" #include "kis_convolution_painter.h" #include "kis_gaussian_kernel.h" #include "kis_fill_painter.h" #include "kis_gradient_painter.h" #include "kis_layer_style_filter_environment.h" #include "kis_selection_filters.h" #include "kis_multiple_projection.h" namespace KisLsUtils { QRect growSelectionUniform(KisPixelSelectionSP selection, int growSize, const QRect &applyRect) { QRect changeRect = applyRect; if (growSize > 0) { KisGrowSelectionFilter filter(growSize, growSize); changeRect = filter.changeRect(applyRect); filter.process(selection, applyRect); } else if (growSize < 0) { KisShrinkSelectionFilter filter(qAbs(growSize), qAbs(growSize), false); changeRect = filter.changeRect(applyRect); filter.process(selection, applyRect); } return changeRect; } KisSelectionSP selectionFromAlphaChannel(KisPaintDeviceSP device, const QRect &srcRect) { const KoColorSpace *cs = device->colorSpace(); KisSelectionSP baseSelection = new KisSelection(new KisSelectionEmptyBounds(0)); KisPixelSelectionSP selection = baseSelection->pixelSelection(); KisSequentialConstIterator srcIt(device, srcRect); KisSequentialIterator dstIt(selection, srcRect); while (srcIt.nextPixel() && dstIt.nextPixel()) { quint8 *dstPtr = dstIt.rawData(); const quint8* srcPtr = srcIt.rawDataConst(); *dstPtr = cs->opacityU8(srcPtr); } return baseSelection; } void findEdge(KisPixelSelectionSP selection, const QRect &applyRect, const bool edgeHidden) { KisSequentialIterator dstIt(selection, applyRect); if (edgeHidden) { while(dstIt.nextPixel()) { quint8 *pixelPtr = dstIt.rawData(); *pixelPtr = (*pixelPtr < 24) ? *pixelPtr * 10 : 0xFF; } } else { while(dstIt.nextPixel()) { quint8 *pixelPtr = dstIt.rawData(); *pixelPtr = 0xFF; } } } QRect growRectFromRadius(const QRect &rc, int radius) { int halfSize = KisGaussianKernel::kernelSizeFromRadius(radius) / 2; return rc.adjusted(-halfSize, -halfSize, halfSize, halfSize); } void applyGaussianWithTransaction(KisPixelSelectionSP selection, const QRect &applyRect, qreal radius) { KisGaussianKernel::applyGaussian(selection, applyRect, radius, radius, QBitArray(), 0, true); } namespace Private { void getGradientTable(const KoAbstractGradient *gradient, QVector *table, const KoColorSpace *colorSpace) { KIS_ASSERT_RECOVER_RETURN(table->size() == 256); for (int i = 0; i < 256; i++) { gradient->colorAt(((*table)[i]), qreal(i) / 255.0); (*table)[i].convertTo(colorSpace); } } struct LinearGradientIndex { int popOneIndex(int selectionAlpha) { return 255 - selectionAlpha; } bool nextPixel() { return true; } }; struct JitterGradientIndex { JitterGradientIndex(const QRect &applyRect, int jitter, const KisLayerStyleFilterEnvironment *env) : randomSelection(env->cachedRandomSelection(applyRect)), noiseIt(randomSelection, applyRect), m_jitterCoeff(jitter * 255 / 100) { } int popOneIndex(int selectionAlpha) { int gradientIndex = 255 - selectionAlpha; gradientIndex += m_jitterCoeff * *noiseIt.rawDataConst() >> 8; gradientIndex &= 0xFF; return gradientIndex; } bool nextPixel() { return noiseIt.nextPixel(); } private: KisPixelSelectionSP randomSelection; KisSequentialConstIterator noiseIt; int m_jitterCoeff; }; template void applyGradientImpl(KisPaintDeviceSP device, KisPixelSelectionSP selection, const QRect &applyRect, const QVector &table, bool edgeHidden, IndexFetcher &indexFetcher) { KIS_ASSERT_RECOVER_RETURN( *table.first().colorSpace() == *device->colorSpace()); const KoColorSpace *cs = device->colorSpace(); const int pixelSize = cs->pixelSize(); KisSequentialConstIterator selIt(selection, applyRect); KisSequentialIterator dstIt(device, applyRect); if (edgeHidden) { while (selIt.nextPixel() && dstIt.nextPixel() && indexFetcher.nextPixel()) { quint8 selAlpha = *selIt.rawDataConst(); int gradientIndex = indexFetcher.popOneIndex(selAlpha); const KoColor &color = table[gradientIndex]; quint8 tableAlpha = color.opacityU8(); memcpy(dstIt.rawData(), color.data(), pixelSize); if (selAlpha < 24 && tableAlpha == 255) { tableAlpha = int(selAlpha) * 10 * tableAlpha >> 8; cs->setOpacity(dstIt.rawData(), tableAlpha, 1); } } } else { while (selIt.nextPixel() && dstIt.nextPixel() && indexFetcher.nextPixel()) { int gradientIndex = indexFetcher.popOneIndex(*selIt.rawDataConst()); const KoColor &color = table[gradientIndex]; memcpy(dstIt.rawData(), color.data(), pixelSize); } } } void applyGradient(KisPaintDeviceSP device, KisPixelSelectionSP selection, const QRect &applyRect, const QVector &table, bool edgeHidden, int jitter, const KisLayerStyleFilterEnvironment *env) { if (!jitter) { LinearGradientIndex fetcher; applyGradientImpl(device, selection, applyRect, table, edgeHidden, fetcher); } else { JitterGradientIndex fetcher(applyRect, jitter, env); applyGradientImpl(device, selection, applyRect, table, edgeHidden, fetcher); } } } const int noiseNeedBorder = 8; void applyNoise(KisPixelSelectionSP selection, const QRect &applyRect, int noise, const psd_layer_effects_context *context, const KisLayerStyleFilterEnvironment *env) { Q_UNUSED(context); const QRect overlayRect = kisGrowRect(applyRect, noiseNeedBorder); KisPixelSelectionSP randomSelection = env->cachedRandomSelection(overlayRect); KisPixelSelectionSP randomOverlay = new KisPixelSelection(); KisSequentialConstIterator noiseIt(randomSelection, overlayRect); KisSequentialConstIterator srcIt(selection, overlayRect); KisRandomAccessorSP dstIt = randomOverlay->createRandomAccessorNG(overlayRect.x(), overlayRect.y()); while (noiseIt.nextPixel() && srcIt.nextPixel()) { int itX = noiseIt.x(); int itY = noiseIt.y(); int x = itX + (*noiseIt.rawDataConst() >> 4) - 8; int y = itY + (*noiseIt.rawDataConst() & 0x0F) - 8; x = (x + itX) >> 1; y = (y + itY) >> 1; dstIt->moveTo(x, y); quint8 dstAlpha = *dstIt->rawData(); quint8 srcAlpha = *srcIt.rawDataConst(); int value = qMin(255, dstAlpha + srcAlpha); *dstIt->rawData() = value; } noise = noise * 255 / 100; KisPainter gc(selection); gc.setOpacity(noise); gc.setCompositeOp(COMPOSITE_COPY); gc.bitBlt(applyRect.topLeft(), randomOverlay, applyRect); } //const int FULL_PERCENT_RANGE = 100; void adjustRange(KisPixelSelectionSP selection, const QRect &applyRect, const int range) { KIS_ASSERT_RECOVER_RETURN(range >= 1 && range <= 100); quint8 rangeTable[256]; for(int i = 0; i < 256; i ++) { quint8 value = i * 100 / range; rangeTable[i] = qMin(value, quint8(255)); } KisSequentialIterator dstIt(selection, applyRect); while (dstIt.nextPixel()) { quint8 *pixelPtr = dstIt.rawData(); *pixelPtr = rangeTable[*pixelPtr]; } } void applyContourCorrection(KisPixelSelectionSP selection, const QRect &applyRect, const quint8 *lookup_table, bool antiAliased, bool edgeHidden) { quint8 contour[PSD_LOOKUP_TABLE_SIZE] = { 0x00, 0x0b, 0x16, 0x21, 0x2c, 0x37, 0x42, 0x4d, 0x58, 0x63, 0x6e, 0x79, 0x84, 0x8f, 0x9a, 0xa5, 0xb0, 0xbb, 0xc6, 0xd1, 0xdc, 0xf2, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; if (edgeHidden) { if (antiAliased) { for (int i = 0; i < PSD_LOOKUP_TABLE_SIZE; i++) { contour[i] = contour[i] * lookup_table[i] >> 8; } } else { for (int i = 0; i < PSD_LOOKUP_TABLE_SIZE; i++) { contour[i] = contour[i] * lookup_table[(int)((int)(i / 2.55) * 2.55 + 0.5)] >> 8; } } } else { if (antiAliased) { for (int i = 0; i < PSD_LOOKUP_TABLE_SIZE; i++) { contour[i] = lookup_table[i]; } } else { for (int i = 0; i < PSD_LOOKUP_TABLE_SIZE; i++) { contour[i] = lookup_table[(int)((int)(i / 2.55) * 2.55 + 0.5)]; } } } KisSequentialIterator dstIt(selection, applyRect); while (dstIt.nextPixel()) { quint8 *pixelPtr = dstIt.rawData(); *pixelPtr = contour[*pixelPtr]; } } void knockOutSelection(KisPixelSelectionSP selection, KisPixelSelectionSP knockOutSelection, const QRect &srcRect, const QRect &dstRect, const QRect &totalNeedRect, const bool knockOutInverted) { KIS_ASSERT_RECOVER_RETURN(knockOutSelection); QRect knockOutRect = !knockOutInverted ? srcRect : totalNeedRect; knockOutRect &= dstRect; KisPainter gc(selection); gc.setCompositeOp(COMPOSITE_ERASE); gc.bitBlt(knockOutRect.topLeft(), knockOutSelection, knockOutRect); } void fillPattern(KisPaintDeviceSP fillDevice, const QRect &applyRect, KisLayerStyleFilterEnvironment *env, int scale, - KoPattern *pattern, + KoPatternSP pattern, int horizontalPhase, int verticalPhase, bool alignWithLayer) { if (scale != 100) { warnKrita << "KisLsOverlayFilter::applyOverlay(): Pattern scaling is NOT implemented!"; } QSize psize(pattern->width(), pattern->height()); QPoint patternOffset(qreal(psize.width()) * horizontalPhase / 100, qreal(psize.height()) * verticalPhase / 100); const QRect boundsRect = alignWithLayer ? env->layerBounds() : env->defaultBounds(); patternOffset += boundsRect.topLeft(); patternOffset.rx() %= psize.width(); patternOffset.ry() %= psize.height(); QRect fillRect = applyRect | applyRect.translated(patternOffset); KisFillPainter gc(fillDevice); gc.fillRect(fillRect.x(), fillRect.y(), fillRect.width(), fillRect.height(), pattern, -patternOffset); gc.end(); } void fillOverlayDevice(KisPaintDeviceSP fillDevice, const QRect &applyRect, const psd_layer_effects_overlay_base *config, KisLayerStyleFilterEnvironment *env) { if (config->fillType() == psd_fill_solid_color) { KoColor color(config->color(), fillDevice->colorSpace()); fillDevice->setDefaultPixel(color); } else if (config->fillType() == psd_fill_pattern) { fillPattern(fillDevice, applyRect, env, config->scale(), config->pattern(), config->horizontalPhase(), config->verticalPhase(), config->alignWithLayer()); } else if (config->fillType() == psd_fill_gradient) { const QRect boundsRect = config->alignWithLayer() ? env->layerBounds() : env->defaultBounds(); QPoint center = boundsRect.center(); center += QPoint(boundsRect.width() * config->gradientXOffset() / 100, boundsRect.height() * config->gradientYOffset() / 100); int width = (boundsRect.width() * config->scale() + 100) / 200; int height = (boundsRect.height() * config->scale() + 100) / 200; /* copy paste from libpsd */ int angle = config->angle(); int corner_angle = (int)(atan((qreal)boundsRect.height() / boundsRect.width()) * 180 / M_PI + 0.5); int sign_x = 1; int sign_y = 1; if(angle < 0) { angle += 360; } if (angle >= 90 && angle < 180) { angle = 180 - angle; sign_x = -1; } else if (angle >= 180 && angle < 270) { angle = angle - 180; sign_x = -1; sign_y = -1; } else if (angle >= 270 && angle <= 360) { angle = 360 - angle; sign_y = -1; } int radius_x = 0; int radius_y = 0; if (angle <= corner_angle) { radius_x = width; radius_y = (int)(radius_x * tan(kisDegreesToRadians(qreal(angle))) + 0.5); } else { radius_y = height; radius_x = (int)(radius_y / tan(kisDegreesToRadians(qreal(angle))) + 0.5); } int radius_corner = (int)(std::sqrt((qreal)(radius_x * radius_x + radius_y * radius_y)) + 0.5); /* end of copy paste from libpsd */ KisGradientPainter gc(fillDevice); - gc.setGradient(config->gradient().data()); + gc.setGradient(config->gradient()); QPointF gradStart; QPointF gradEnd; KisGradientPainter::enumGradientRepeat repeat = KisGradientPainter::GradientRepeatNone; QPoint rectangularOffset(sign_x * radius_x, -sign_y * radius_y); switch(config->style()) { case psd_gradient_style_linear: gc.setGradientShape(KisGradientPainter::GradientShapeLinear); repeat = KisGradientPainter::GradientRepeatNone; gradStart = center - rectangularOffset; gradEnd = center + rectangularOffset; break; case psd_gradient_style_radial: gc.setGradientShape(KisGradientPainter::GradientShapeRadial); repeat = KisGradientPainter::GradientRepeatNone; gradStart = center; gradEnd = center + QPointF(radius_corner, 0); break; case psd_gradient_style_angle: gc.setGradientShape(KisGradientPainter::GradientShapeConical); repeat = KisGradientPainter::GradientRepeatNone; gradStart = center; gradEnd = center + rectangularOffset; break; case psd_gradient_style_reflected: gc.setGradientShape(KisGradientPainter::GradientShapeLinear); repeat = KisGradientPainter::GradientRepeatAlternate; gradStart = center - rectangularOffset; gradEnd = center; break; case psd_gradient_style_diamond: gc.setGradientShape(KisGradientPainter::GradientShapeBiLinear); repeat = KisGradientPainter::GradientRepeatNone; gradStart = center - rectangularOffset; gradEnd = center + rectangularOffset; break; default: qFatal("Gradient Overlay: unknown switch case!"); break; } gc.paintGradient(gradStart, gradEnd, repeat, 0.0, config->reverse(), applyRect); } } void applyFinalSelection(const QString &projectionId, KisSelectionSP baseSelection, KisPaintDeviceSP srcDevice, KisMultipleProjection *dst, const QRect &/*srcRect*/, const QRect &dstRect, const psd_layer_effects_context */*context*/, const psd_layer_effects_shadow_base *config, const KisLayerStyleFilterEnvironment *env) { const KoColor effectColor(config->color(), srcDevice->colorSpace()); const QRect effectRect(dstRect); const QString compositeOp = config->blendMode(); const quint8 opacityU8 = 255.0 / 100.0 * config->opacity(); KisPaintDeviceSP dstDevice = dst->getProjection(projectionId, compositeOp, opacityU8, QBitArray(), srcDevice); if (config->fillType() == psd_fill_solid_color) { KisFillPainter gc(dstDevice); gc.setCompositeOp(COMPOSITE_COPY); gc.setSelection(baseSelection); gc.fillSelection(effectRect, effectColor); gc.end(); } else if (config->fillType() == psd_fill_gradient) { if (!config->gradient()) { warnKrita << "KisLsUtils::applyFinalSelection: Gradient object is null! Skipping..."; return; } QVector table(256); Private::getGradientTable(config->gradient().data(), &table, dstDevice->colorSpace()); Private::applyGradient(dstDevice, baseSelection->pixelSelection(), effectRect, table, true, config->jitter(), env); } //dstDevice->convertToQImage(0, QRect(0,0,300,300)).save("6_device_shadow.png"); } bool checkEffectEnabled(const psd_layer_effects_shadow_base *config, KisMultipleProjection *dst) { bool result = config->effectEnabled(); if (!result) { dst->freeAllProjections(); } return result; } } diff --git a/libs/image/layerstyles/kis_ls_utils.h b/libs/image/layerstyles/kis_ls_utils.h index 4dacfc3e37..b5c848c873 100644 --- a/libs/image/layerstyles/kis_ls_utils.h +++ b/libs/image/layerstyles/kis_ls_utils.h @@ -1,126 +1,126 @@ /* * 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. */ #ifndef __KIS_LS_UTILS_H #define __KIS_LS_UTILS_H #include "kis_types.h" #include "kis_lod_transform.h" - +#include struct psd_layer_effects_context; class psd_layer_effects_shadow_base; struct psd_layer_effects_overlay_base; class KisLayerStyleFilterEnvironment; -class KoPattern; + class KisMultipleProjection; namespace KisLsUtils { QRect growSelectionUniform(KisPixelSelectionSP selection, int growSize, const QRect &applyRect); KisSelectionSP selectionFromAlphaChannel(KisPaintDeviceSP device, const QRect &srcRect); void findEdge(KisPixelSelectionSP selection, const QRect &applyRect, const bool edgeHidden); QRect growRectFromRadius(const QRect &rc, int radius); void applyGaussianWithTransaction(KisPixelSelectionSP selection, const QRect &applyRect, qreal radius); static const int FULL_PERCENT_RANGE = 100; void adjustRange(KisPixelSelectionSP selection, const QRect &applyRect, const int range); void applyContourCorrection(KisPixelSelectionSP selection, const QRect &applyRect, const quint8 *lookup_table, bool antiAliased, bool edgeHidden); extern const int noiseNeedBorder; void applyNoise(KisPixelSelectionSP selection, const QRect &applyRect, int noise, const psd_layer_effects_context *context, const KisLayerStyleFilterEnvironment *env); void knockOutSelection(KisPixelSelectionSP selection, KisPixelSelectionSP knockOutSelection, const QRect &srcRect, const QRect &dstRect, const QRect &totalNeedRect, const bool knockOutInverted); void fillPattern(KisPaintDeviceSP fillDevice, const QRect &applyRect, KisLayerStyleFilterEnvironment *env, int scale, - KoPattern *pattern, + KoPatternSP pattern, int horizontalPhase, int verticalPhase, bool alignWithLayer); void fillOverlayDevice(KisPaintDeviceSP fillDevice, const QRect &applyRect, const psd_layer_effects_overlay_base *config, KisLayerStyleFilterEnvironment *env); void applyFinalSelection(const QString &projectionId, KisSelectionSP baseSelection, KisPaintDeviceSP srcDevice, KisMultipleProjection *dst, const QRect &srcRect, const QRect &dstRect, const psd_layer_effects_context *context, const psd_layer_effects_shadow_base *config, const KisLayerStyleFilterEnvironment *env); bool checkEffectEnabled(const psd_layer_effects_shadow_base *config, KisMultipleProjection *dst); template struct LodWrapper { LodWrapper(int lod, const ConfigStruct *srcStruct) { if (lod > 0) { storage.reset(new ConfigStruct(*srcStruct)); const qreal lodScale = KisLodTransform::lodToScale(lod); storage->scaleLinearSizes(lodScale); config = storage.data(); } else { config = srcStruct; } } const ConfigStruct *config; private: QScopedPointer storage; }; } #endif /* __KIS_LS_UTILS_H */ diff --git a/libs/image/tests/kis_asl_parser_test.cpp b/libs/image/tests/kis_asl_parser_test.cpp index 9f3f6e8857..dec4faa453 100644 --- a/libs/image/tests/kis_asl_parser_test.cpp +++ b/libs/image/tests/kis_asl_parser_test.cpp @@ -1,331 +1,331 @@ /* * 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 KoPattern *pattern) { + 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); - KoPattern testPattern1(testImage, "Some very nice name ;)", ""); - KoPattern testPattern2(testImage, "Another very nice name ;P", ""); + KoPatternSP testPattern1(new KoPattern(testImage, "Some very nice name ;)", "")); + KoPatternSP testPattern2(new KoPattern(testImage, "Another very nice name ;P", "")); w.enterList("Patterns"); - w.writePattern("", &testPattern1); - w.writePattern("", &testPattern2); + 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)); 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) + QDir::separator() + "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)); KisAslXmlParser parser; parser.parseXML(doc, c); //QCOMPARE(verifier.m_numCallsHappened, 7); index++; //break; } } QTEST_MAIN(KisAslParserTest) diff --git a/libs/image/tests/kis_gradient_painter_test.cpp b/libs/image/tests/kis_gradient_painter_test.cpp index cd2a2fa0ae..7bf6b9a1a8 100644 --- a/libs/image/tests/kis_gradient_painter_test.cpp +++ b/libs/image/tests/kis_gradient_painter_test.cpp @@ -1,334 +1,333 @@ /* * Copyright (c) 2007 Boudewijn Rempt boud@valdyas.org * * 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_gradient_painter_test.h" #include #include "kis_gradient_painter.h" #include "kis_paint_device.h" #include "kis_selection.h" #include #include #include #include #include #include "krita_utils.h" #include "testutil.h" void KisGradientPainterTest::testSimplifyPath() { QPolygonF selectionPolygon; selectionPolygon << QPointF(100, 100); selectionPolygon << QPointF(200, 100); selectionPolygon << QPointF(202, 100); selectionPolygon << QPointF(200, 200); selectionPolygon << QPointF(100, 200); selectionPolygon << QPointF(100, 102); QPainterPath path; path.addPolygon(selectionPolygon); QPainterPath simplifiedPath; simplifiedPath = KritaUtils::trySimplifyPath(path, 10.0); QPainterPath ref; ref.moveTo(100,100); ref.lineTo(200,100); ref.lineTo(200,200); ref.lineTo(100,200); QCOMPARE(simplifiedPath, ref); } void testShapedGradientPainterImpl(const QPolygonF &selectionPolygon, const QString &testName, const QPolygonF &selectionErasePolygon = QPolygonF()) { const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisPaintDeviceSP dev = new KisPaintDevice(cs); QRect imageRect(0,0,300,300); KisSelectionSP selection = new KisSelection(); KisPixelSelectionSP pixelSelection = selection->pixelSelection(); KisPainter selPainter(pixelSelection); selPainter.setFillStyle(KisPainter::FillStyleForegroundColor); selPainter.setPaintColor(KoColor(Qt::white, pixelSelection->colorSpace())); selPainter.paintPolygon(selectionPolygon); if (!selectionErasePolygon.isEmpty()) { selPainter.setCompositeOp(COMPOSITE_ERASE); selPainter.setPaintColor(KoColor(Qt::white, pixelSelection->colorSpace())); selPainter.paintPolygon(selectionErasePolygon); } selPainter.end(); pixelSelection->invalidateOutlineCache(); pixelSelection->convertToQImage(0, imageRect).save("sgt_selection.png"); QLinearGradient testGradient; testGradient.setColorAt(0.0, Qt::white); testGradient.setColorAt(0.5, Qt::green); testGradient.setColorAt(1.0, Qt::black); testGradient.setSpread(QGradient::ReflectSpread); - QScopedPointer gradient( - KoStopGradient::fromQGradient(&testGradient)); + QSharedPointer gradient(KoStopGradient::fromQGradient(&testGradient)); KisGradientPainter gc(dev, selection); - gc.setGradient(gradient.data()); + gc.setGradient(gradient); gc.setGradientShape(KisGradientPainter::GradientShapePolygonal); gc.paintGradient(selectionPolygon.boundingRect().topLeft(), selectionPolygon.boundingRect().bottomRight(), KisGradientPainter::GradientRepeatNone, 0, false, imageRect.x(), imageRect.y(), imageRect.width(), imageRect.height()); QVERIFY(TestUtil::checkQImageExternal(dev->convertToQImage(0, imageRect), "shaped_gradient", "fill", testName, 1, 1, 0)); } void KisGradientPainterTest::testShapedGradientPainterRect() { QPolygonF selectionPolygon; selectionPolygon << QPointF(100, 100); selectionPolygon << QPointF(200, 100); selectionPolygon << QPointF(202, 100); selectionPolygon << QPointF(200, 200); selectionPolygon << QPointF(100, 200); testShapedGradientPainterImpl(selectionPolygon, "rect_shape"); } void KisGradientPainterTest::testShapedGradientPainterRectPierced() { QPolygonF selectionPolygon; selectionPolygon << QPointF(100, 100); selectionPolygon << QPointF(200, 100); selectionPolygon << QPointF(200, 200); selectionPolygon << QPointF(100, 200); QPolygonF selectionErasePolygon; selectionErasePolygon << QPointF(150, 150); selectionErasePolygon << QPointF(155, 150); selectionErasePolygon << QPointF(155, 155); selectionErasePolygon << QPointF(150, 155); testShapedGradientPainterImpl(selectionPolygon, "rect_shape_pierced", selectionErasePolygon); } void KisGradientPainterTest::testShapedGradientPainterNonRegular() { QPolygonF selectionPolygon; selectionPolygon << QPointF(100, 100); selectionPolygon << QPointF(200, 120); selectionPolygon << QPointF(170, 140); selectionPolygon << QPointF(200, 180); selectionPolygon << QPointF(30, 220); testShapedGradientPainterImpl(selectionPolygon, "nonregular_shape"); } void KisGradientPainterTest::testShapedGradientPainterNonRegularPierced() { QPolygonF selectionPolygon; selectionPolygon << QPointF(100, 100); selectionPolygon << QPointF(200, 120); selectionPolygon << QPointF(170, 140); selectionPolygon << QPointF(200, 180); selectionPolygon << QPointF(30, 220); QPolygonF selectionErasePolygon; selectionErasePolygon << QPointF(150, 150); selectionErasePolygon << QPointF(155, 150); selectionErasePolygon << QPointF(155, 155); selectionErasePolygon << QPointF(150, 155); testShapedGradientPainterImpl(selectionPolygon, "nonregular_shape_pierced", selectionErasePolygon); } #include "kis_polygonal_gradient_shape_strategy.h" void KisGradientPainterTest::testFindShapedExtremums() { QPolygonF selectionPolygon; selectionPolygon << QPointF(100, 100); selectionPolygon << QPointF(200, 120); selectionPolygon << QPointF(170, 140); selectionPolygon << QPointF(200, 180); selectionPolygon << QPointF(30, 220); QPolygonF selectionErasePolygon; selectionErasePolygon << QPointF(101, 101); selectionErasePolygon << QPointF(190, 120); selectionErasePolygon << QPointF(160, 140); selectionErasePolygon << QPointF(200, 180); selectionErasePolygon << QPointF(30, 220); QPainterPath path; path.addPolygon(selectionPolygon); path.closeSubpath(); path.addPolygon(selectionErasePolygon); path.closeSubpath(); QPointF center = KisPolygonalGradientShapeStrategy::testingCalculatePathCenter( 4, path, 2.0, true); dbgKrita << ppVar(center); QVERIFY(path.contains(center)); } void KisGradientPainterTest::testSplitDisjointPaths() { QPainterPath path; // small bug: the smaller rect is also merged path.addRect(QRectF(323, 123, 4, 4)); path.addRect(QRectF(300, 100, 50, 50)); path.addRect(QRectF(320, 120, 10, 10)); path.addRect(QRectF(200, 100, 50, 50)); path.addRect(QRectF(240, 120, 70, 10)); path.addRect(QRectF(100, 100, 50, 50)); path.addRect(QRectF(120, 120, 10, 10)); path = path.simplified(); { QImage srcImage(450, 250, QImage::Format_ARGB32); srcImage.fill(0); QPainter gc(&srcImage); gc.fillPath(path, Qt::red); //srcImage.save("src_disjoint_paths.png"); } QList result = KritaUtils::splitDisjointPaths(path); { QImage dstImage(450, 250, QImage::Format_ARGB32); dstImage.fill(0); QPainter gc(&dstImage); QVector brushes; brushes << Qt::red; brushes << Qt::green; brushes << Qt::blue; brushes << Qt::cyan; brushes << Qt::magenta; brushes << Qt::yellow; brushes << Qt::black; brushes << Qt::white; int index = 0; Q_FOREACH (const QPainterPath &p, result) { gc.fillPath(p, brushes[index]); index = (index + 1) % brushes.size(); } TestUtil::checkQImageExternal(dstImage, "shaped_gradient", "test", "disjoint_paths"); } } #include "kis_cached_gradient_shape_strategy.h" #include #include #include #include #include using namespace boost::accumulators; void KisGradientPainterTest::testCachedStrategy() { QPolygonF selectionPolygon; selectionPolygon << QPointF(100, 100); selectionPolygon << QPointF(200, 120); selectionPolygon << QPointF(170, 140); selectionPolygon << QPointF(200, 180); selectionPolygon << QPointF(30, 220); QPainterPath selectionPath; selectionPath.addPolygon(selectionPolygon); QRect rc = selectionPolygon.boundingRect().toAlignedRect(); KisGradientShapeStrategy *strategy = new KisPolygonalGradientShapeStrategy(selectionPath, 2.0); KisCachedGradientShapeStrategy cached(rc, 4, 4, strategy); accumulator_set > accum; const qreal maxRelError = 5.0 / 256; for (int y = rc.y(); y <= rc.bottom(); y++) { for (int x = rc.x(); x <= rc.right(); x++) { if (!selectionPolygon.containsPoint(QPointF(x, y), Qt::OddEvenFill)) continue; qreal ref = strategy->valueAt(x, y); qreal value = cached.valueAt(x, y); if (ref == 0.0) continue; qreal relError = (ref - value)/* / ref*/; accum(relError); if (relError > maxRelError) { //dbgKrita << ppVar(x) << ppVar(y) << ppVar(value) << ppVar(ref) << ppVar(relError); } } } dbgKrita << ppVar(count(accum)); dbgKrita << ppVar(mean(accum)); dbgKrita << ppVar(variance(accum)); dbgKrita << ppVar((min)(accum)); dbgKrita << ppVar((max)(accum)); qreal varError = variance(accum); QVERIFY(varError < maxRelError); qreal maxError = qMax(qAbs((min)(accum)), qAbs((max)(accum))); QVERIFY(maxError < 2 * maxRelError); } QTEST_MAIN(KisGradientPainterTest) diff --git a/libs/image/tests/kis_layer_style_projection_plane_test.cpp b/libs/image/tests/kis_layer_style_projection_plane_test.cpp index 52105b92b5..46978c18f9 100644 --- a/libs/image/tests/kis_layer_style_projection_plane_test.cpp +++ b/libs/image/tests/kis_layer_style_projection_plane_test.cpp @@ -1,499 +1,499 @@ /* * 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_layer_style_projection_plane_test.h" #include #include "testutil.h" #include #include #include #include #include "kis_transparency_mask.h" #include "kis_paint_layer.h" #include "kis_image.h" #include "kis_painter.h" #include "kis_selection.h" #include "kis_pixel_selection.h" #include "layerstyles/kis_layer_style_projection_plane.h" #include "kis_psd_layer_style.h" #include "kis_paint_device_debug_utils.h" void KisLayerStyleProjectionPlaneTest::test(KisPSDLayerStyleSP style, const QString testName) { const QRect imageRect(0, 0, 200, 200); const QRect rFillRect(10, 10, 100, 100); const QRect tMaskRect(50, 50, 20, 20); const QRect partialSelectionRect(90, 50, 20, 20); const QRect updateRect1(10, 10, 50, 100); const QRect updateRect2(60, 10, 50, 100); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(0, imageRect.width(), imageRect.height(), cs, "styles test"); KisPaintLayerSP layer = new KisPaintLayer(image, "test", OPACITY_OPAQUE_U8); image->addNode(layer); KisLayerStyleProjectionPlane plane(layer.data(), style); KIS_DUMP_DEVICE_2(layer->projection(), imageRect, "00L_initial", testName); //layer->paintDevice()->fill(rFillRect, KoColor(Qt::red, cs)); { KisPainter gc(layer->paintDevice()); gc.setPaintColor(KoColor(Qt::red, cs)); gc.setFillStyle(KisPainter::FillStyleForegroundColor); gc.paintEllipse(rFillRect); } KIS_DUMP_DEVICE_2(layer->projection(), imageRect, "01L_fill", testName); KisPaintDeviceSP projection = new KisPaintDevice(cs); { const QRect changeRect = plane.changeRect(rFillRect, KisLayer::N_FILTHY); dbgKrita << ppVar(rFillRect) << ppVar(changeRect); plane.recalculate(changeRect, layer); KIS_DUMP_DEVICE_2(layer->projection(), imageRect, "02L_recalculate_fill", testName); KisPainter painter(projection); plane.apply(&painter, changeRect); KIS_DUMP_DEVICE_2(projection, imageRect, "03P_apply_on_fill", testName); } //return; KisTransparencyMaskSP transparencyMask = new KisTransparencyMask(); KisSelectionSP selection = new KisSelection(); selection->pixelSelection()->select(tMaskRect, OPACITY_OPAQUE_U8); transparencyMask->setSelection(selection); image->addNode(transparencyMask, layer); KIS_DUMP_DEVICE_2(layer->projection(), imageRect, "04L_mask_added", testName); plane.recalculate(imageRect, layer); KIS_DUMP_DEVICE_2(layer->projection(), imageRect, "05L_mask_added_recalculated", testName); { projection->clear(); KisPainter painter(projection); plane.apply(&painter, imageRect); KIS_DUMP_DEVICE_2(projection, imageRect, "06P_apply_on_mask", testName); } selection->pixelSelection()->select(partialSelectionRect, OPACITY_OPAQUE_U8); { const QRect changeRect = plane.changeRect(partialSelectionRect, KisLayer::N_FILTHY); projection->clear(changeRect); dbgKrita << ppVar(partialSelectionRect) << ppVar(changeRect); plane.recalculate(changeRect, layer); KIS_DUMP_DEVICE_2(layer->projection(), imageRect, "07L_recalculate_partial", testName); KisPainter painter(projection); plane.apply(&painter, changeRect); KIS_DUMP_DEVICE_2(projection, imageRect, "08P_apply_partial", testName); } // half updates transparencyMask->setVisible(false); { const QRect changeRect = plane.changeRect(updateRect1, KisLayer::N_FILTHY); projection->clear(changeRect); dbgKrita << ppVar(updateRect1) << ppVar(changeRect); plane.recalculate(changeRect, layer); KIS_DUMP_DEVICE_2(layer->projection(), imageRect, "09L_recalculate_half1", testName); KisPainter painter(projection); plane.apply(&painter, changeRect); KIS_DUMP_DEVICE_2(projection, imageRect, "10P_apply_half1", testName); } { const QRect changeRect = plane.changeRect(updateRect2, KisLayer::N_FILTHY); projection->clear(changeRect); dbgKrita << ppVar(updateRect2) << ppVar(changeRect); plane.recalculate(changeRect, layer); KIS_DUMP_DEVICE_2(layer->projection(), imageRect, "09L_recalculate_half1", testName); KisPainter painter(projection); plane.apply(&painter, changeRect); KIS_DUMP_DEVICE_2(projection, imageRect, "10P_apply_half2", testName); } } void KisLayerStyleProjectionPlaneTest::testShadow() { KisPSDLayerStyleSP style(new KisPSDLayerStyle()); style->dropShadow()->setSize(15); style->dropShadow()->setDistance(15); style->dropShadow()->setOpacity(70); style->dropShadow()->setNoise(30); style->dropShadow()->setEffectEnabled(true); style->innerShadow()->setSize(10); style->innerShadow()->setSpread(10); style->innerShadow()->setDistance(5); style->innerShadow()->setOpacity(70); style->innerShadow()->setNoise(30); style->innerShadow()->setEffectEnabled(true); test(style, "shadow"); } void KisLayerStyleProjectionPlaneTest::testGlow() { KisPSDLayerStyleSP style(new KisPSDLayerStyle()); style->outerGlow()->setSize(15); style->outerGlow()->setSpread(10); style->outerGlow()->setOpacity(70); style->outerGlow()->setNoise(30); style->outerGlow()->setEffectEnabled(true); style->outerGlow()->setColor(Qt::green); test(style, "glow_outer"); } #include void KisLayerStyleProjectionPlaneTest::testGlowGradient() { KisPSDLayerStyleSP style(new KisPSDLayerStyle()); style->outerGlow()->setSize(15); style->outerGlow()->setSpread(10); style->outerGlow()->setOpacity(70); style->outerGlow()->setNoise(10); style->outerGlow()->setEffectEnabled(true); style->outerGlow()->setColor(Qt::green); QLinearGradient testGradient; testGradient.setColorAt(0.0, Qt::white); testGradient.setColorAt(0.5, Qt::green); testGradient.setColorAt(1.0, Qt::black); testGradient.setSpread(QGradient::ReflectSpread); QSharedPointer gradient( KoStopGradient::fromQGradient(&testGradient)); style->outerGlow()->setGradient(gradient); style->outerGlow()->setFillType(psd_fill_gradient); test(style, "glow_outer_grad"); } void KisLayerStyleProjectionPlaneTest::testGlowGradientJitter() { KisPSDLayerStyleSP style(new KisPSDLayerStyle()); style->outerGlow()->setSize(15); style->outerGlow()->setSpread(10); style->outerGlow()->setOpacity(70); style->outerGlow()->setNoise(0); style->outerGlow()->setEffectEnabled(true); style->outerGlow()->setColor(Qt::green); QLinearGradient testGradient; testGradient.setColorAt(0.0, Qt::white); testGradient.setColorAt(0.5, Qt::green); testGradient.setColorAt(1.0, Qt::black); testGradient.setSpread(QGradient::ReflectSpread); QSharedPointer gradient( KoStopGradient::fromQGradient(&testGradient)); style->outerGlow()->setGradient(gradient); style->outerGlow()->setFillType(psd_fill_gradient); style->outerGlow()->setJitter(20); test(style, "glow_outer_grad_jit"); } void KisLayerStyleProjectionPlaneTest::testGlowInnerGradient() { KisPSDLayerStyleSP style(new KisPSDLayerStyle()); style->innerGlow()->setSize(15); style->innerGlow()->setSpread(10); style->innerGlow()->setOpacity(80); style->innerGlow()->setNoise(10); style->innerGlow()->setEffectEnabled(true); style->innerGlow()->setColor(Qt::white); QLinearGradient testGradient; testGradient.setColorAt(0.0, Qt::white); testGradient.setColorAt(0.5, Qt::green); testGradient.setColorAt(1.0, Qt::black); testGradient.setSpread(QGradient::ReflectSpread); QSharedPointer gradient( KoStopGradient::fromQGradient(&testGradient)); style->innerGlow()->setGradient(gradient); style->innerGlow()->setFillType(psd_fill_gradient); test(style, "glow_inner_grad"); style->innerGlow()->setFillType(psd_fill_solid_color); style->innerGlow()->setSource(psd_glow_center); test(style, "glow_inner_grad_center"); } #include void KisLayerStyleProjectionPlaneTest::testSatin() { KisPSDLayerStyleSP style(new KisPSDLayerStyle()); style->satin()->setSize(15); style->satin()->setOpacity(80); style->satin()->setAngle(180); style->satin()->setEffectEnabled(true); style->satin()->setColor(Qt::white); style->satin()->setBlendMode(COMPOSITE_LINEAR_DODGE); test(style, "satin"); } void KisLayerStyleProjectionPlaneTest::testColorOverlay() { KisPSDLayerStyleSP style(new KisPSDLayerStyle()); style->colorOverlay()->setOpacity(80); style->colorOverlay()->setEffectEnabled(true); style->colorOverlay()->setColor(Qt::white); style->colorOverlay()->setBlendMode(COMPOSITE_LINEAR_DODGE); test(style, "color_overlay"); } void KisLayerStyleProjectionPlaneTest::testGradientOverlay() { KisPSDLayerStyleSP style(new KisPSDLayerStyle()); style->gradientOverlay()->setAngle(90); style->gradientOverlay()->setOpacity(80); style->gradientOverlay()->setEffectEnabled(true); style->gradientOverlay()->setBlendMode(COMPOSITE_LINEAR_DODGE); style->gradientOverlay()->setAlignWithLayer(true); style->gradientOverlay()->setScale(100); style->gradientOverlay()->setStyle(psd_gradient_style_diamond); QLinearGradient testGradient; testGradient.setColorAt(0.0, Qt::white); testGradient.setColorAt(0.5, Qt::green); testGradient.setColorAt(1.0, Qt::black); testGradient.setSpread(QGradient::ReflectSpread); QSharedPointer gradient( KoStopGradient::fromQGradient(&testGradient)); style->gradientOverlay()->setGradient(gradient); test(style, "grad_overlay"); } void KisLayerStyleProjectionPlaneTest::testPatternOverlay() { KisPSDLayerStyleSP style(new KisPSDLayerStyle()); style->patternOverlay()->setOpacity(80); style->patternOverlay()->setEffectEnabled(true); style->patternOverlay()->setBlendMode(COMPOSITE_LINEAR_DODGE); style->patternOverlay()->setScale(100); style->patternOverlay()->setAlignWithLayer(false); QString fileName(TestUtil::fetchDataFileLazy("pattern.pat")); - KoPattern pattern(fileName); - QVERIFY(pattern.load()); + KoPatternSP pattern(new KoPattern(fileName)); + QVERIFY(pattern->load()); - style->patternOverlay()->setPattern(&pattern); + style->patternOverlay()->setPattern(pattern); test(style, "pat_overlay"); } void KisLayerStyleProjectionPlaneTest::testStroke() { KisPSDLayerStyleSP style(new KisPSDLayerStyle()); style->stroke()->setColor(Qt::blue); style->stroke()->setOpacity(80); style->stroke()->setEffectEnabled(true); style->stroke()->setBlendMode(COMPOSITE_OVER); style->stroke()->setSize(3); style->stroke()->setPosition(psd_stroke_center); test(style, "stroke_col_ctr"); style->stroke()->setPosition(psd_stroke_outside); test(style, "stroke_col_out"); style->stroke()->setPosition(psd_stroke_inside); test(style, "stroke_col_in"); QString fileName(TestUtil::fetchDataFileLazy("pattern.pat")); - KoPattern pattern(fileName); - QVERIFY(pattern.load()); - style->stroke()->setPattern(&pattern); + KoPatternSP pattern(new KoPattern(fileName)); + QVERIFY(pattern->load()); + style->stroke()->setPattern(pattern); style->stroke()->setFillType(psd_fill_pattern); test(style, "stroke_pat"); QLinearGradient testGradient; testGradient.setColorAt(0.0, Qt::white); testGradient.setColorAt(0.5, Qt::green); testGradient.setColorAt(1.0, Qt::black); testGradient.setSpread(QGradient::ReflectSpread); QSharedPointer gradient( KoStopGradient::fromQGradient(&testGradient)); style->stroke()->setGradient(gradient); style->stroke()->setFillType(psd_fill_gradient); test(style, "stroke_grad"); } #include "layerstyles/gimp_bump_map.h" void KisLayerStyleProjectionPlaneTest::testBumpmap() { KisPixelSelectionSP device = new KisPixelSelection(); const int numCycles = 30; const int step = 5; QRect applyRect(200, 100, 100, 100); QRect fillRect(210, 110, 80, 80); quint8 selectedness = 256 - numCycles * step; for (int i = 0; i < numCycles; i++) { device->select(fillRect, selectedness); fillRect = kisGrowRect(fillRect, -1); selectedness += step; } KIS_DUMP_DEVICE_2(device, applyRect, "00_initial", "bumpmap"); bumpmap_vals_t bmvals; bmvals.azimuth = 240; bmvals.elevation = 30; bmvals.depth = 50; bmvals.ambient = 128; bmvals.compensate = false; bmvals.invert = false; bmvals.type = 0; bumpmap(device, applyRect, bmvals); KIS_DUMP_DEVICE_2(device, applyRect, "01_bumpmapped", "bumpmap"); } void KisLayerStyleProjectionPlaneTest::testBevel() { KisPSDLayerStyleSP style(new KisPSDLayerStyle()); style->bevelAndEmboss()->setEffectEnabled(true); style->bevelAndEmboss()->setAngle(135); style->bevelAndEmboss()->setAltitude(45); style->bevelAndEmboss()->setDepth(100); style->bevelAndEmboss()->setHighlightColor(Qt::white); style->bevelAndEmboss()->setHighlightBlendMode(COMPOSITE_OVER); style->bevelAndEmboss()->setHighlightOpacity(100); style->bevelAndEmboss()->setShadowColor(Qt::black); style->bevelAndEmboss()->setShadowBlendMode(COMPOSITE_OVER); style->bevelAndEmboss()->setShadowOpacity(100); QString fileName(TestUtil::fetchDataFileLazy("pattern.pat")); - KoPattern pattern(fileName); - QVERIFY(pattern.load()); + KoPatternSP pattern(new KoPattern(fileName)); + QVERIFY(pattern->load()); - style->bevelAndEmboss()->setTexturePattern(&pattern); + style->bevelAndEmboss()->setTexturePattern(pattern); style->bevelAndEmboss()->setTextureEnabled(true); style->bevelAndEmboss()->setTextureDepth(-10); style->bevelAndEmboss()->setTextureInvert(false); style->bevelAndEmboss()->setStyle(psd_bevel_outer_bevel); style->bevelAndEmboss()->setDirection(psd_direction_up); style->bevelAndEmboss()->setSoften(0); test(style, "bevel_outer_up"); style->bevelAndEmboss()->setTextureInvert(true); style->bevelAndEmboss()->setStyle(psd_bevel_outer_bevel); style->bevelAndEmboss()->setDirection(psd_direction_up); style->bevelAndEmboss()->setSoften(0); test(style, "bevel_outer_up_invert_texture"); style->bevelAndEmboss()->setTextureInvert(false); style->bevelAndEmboss()->setStyle(psd_bevel_outer_bevel); style->bevelAndEmboss()->setDirection(psd_direction_down); style->bevelAndEmboss()->setSoften(0); test(style, "bevel_outer_down"); style->bevelAndEmboss()->setStyle(psd_bevel_emboss); style->bevelAndEmboss()->setDirection(psd_direction_up); style->bevelAndEmboss()->setSoften(0); test(style, "bevel_emboss_up"); style->bevelAndEmboss()->setStyle(psd_bevel_pillow_emboss); style->bevelAndEmboss()->setDirection(psd_direction_up); style->bevelAndEmboss()->setSoften(0); test(style, "bevel_pillow_up"); style->bevelAndEmboss()->setStyle(psd_bevel_pillow_emboss); style->bevelAndEmboss()->setDirection(psd_direction_down); style->bevelAndEmboss()->setSoften(0); test(style, "bevel_pillow_down"); style->bevelAndEmboss()->setStyle(psd_bevel_pillow_emboss); style->bevelAndEmboss()->setDirection(psd_direction_up); style->bevelAndEmboss()->setSoften(3); test(style, "bevel_pillow_up_soft"); } QTEST_MAIN(KisLayerStyleProjectionPlaneTest) diff --git a/libs/libkis/Krita.cpp b/libs/libkis/Krita.cpp index 48df9ca5c1..fab9fdf42b 100644 --- a/libs/libkis/Krita.cpp +++ b/libs/libkis/Krita.cpp @@ -1,423 +1,423 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program 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 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 Lesser 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.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "View.h" #include "Document.h" #include "Window.h" #include "Extension.h" #include "DockWidgetFactoryBase.h" #include "Filter.h" #include "InfoObject.h" #include "Resource.h" Krita* Krita::s_instance = 0; struct Krita::Private { Private() {} QList extensions; bool batchMode {false}; Notifier *notifier{new Notifier()}; }; Krita::Krita(QObject *parent) : QObject(parent) , d(new Private) { qRegisterMetaType(); connect(KisPart::instance(), SIGNAL(sigWindowAdded(KisMainWindow*)), SLOT(mainWindowAdded(KisMainWindow*))); } Krita::~Krita() { qDeleteAll(d->extensions); delete d->notifier; delete d; } QList Krita::actions() const { KisMainWindow *mainWindow = KisPart::instance()->currentMainwindow(); if (!mainWindow) { return QList(); } KActionCollection *actionCollection = mainWindow->actionCollection(); return actionCollection->actions(); } QAction *Krita::action(const QString &name) const { KisMainWindow *mainWindow = KisPart::instance()->currentMainwindow(); if (!mainWindow) { return 0; } KActionCollection *actionCollection = mainWindow->actionCollection(); QAction *action = actionCollection->action(name); return action; } Document* Krita::activeDocument() const { KisMainWindow *mainWindow = KisPart::instance()->currentMainwindow(); if (!mainWindow) { return 0; } KisView *view = mainWindow->activeView(); if (!view) { return 0; } KisDocument *document = view->document(); return new Document(document); } void Krita::setActiveDocument(Document* value) { Q_FOREACH(KisView *view, KisPart::instance()->views()) { if (view->document() == value->document().data()) { view->activateWindow(); break; } } } bool Krita::batchmode() const { return d->batchMode; } void Krita::setBatchmode(bool value) { d->batchMode = value; } QList Krita::documents() const { QList ret; foreach(QPointer doc, KisPart::instance()->documents()) { ret << new Document(doc); } return ret; } QStringList Krita::filters() const { QStringList ls = KisFilterRegistry::instance()->keys(); std::sort(ls.begin(), ls.end()); return ls; } Filter *Krita::filter(const QString &name) const { if (!filters().contains(name)) return 0; Filter *filter = new Filter(); filter->setName(name); KisFilterSP f = KisFilterRegistry::instance()->value(name); KisFilterConfigurationSP fc = f->defaultConfiguration(); InfoObject *info = new InfoObject(fc); filter->setConfiguration(info); return filter; } QStringList Krita::colorModels() const { QSet colorModelsIds; QList ids = KoColorSpaceRegistry::instance()->colorModelsList(KoColorSpaceRegistry::AllColorSpaces); Q_FOREACH(KoID id, ids) { colorModelsIds << id.id(); } return colorModelsIds.toList(); } QStringList Krita::colorDepths(const QString &colorModel) const { QSet colorDepthsIds; QList ids = KoColorSpaceRegistry::instance()->colorDepthList(colorModel, KoColorSpaceRegistry::AllColorSpaces); Q_FOREACH(KoID id, ids) { colorDepthsIds << id.id(); } return colorDepthsIds.toList(); } QStringList Krita::filterStrategies() const { return KisFilterStrategyRegistry::instance()->keys(); } QStringList Krita::profiles(const QString &colorModel, const QString &colorDepth) const { QSet profileNames; QString id = KoColorSpaceRegistry::instance()->colorSpaceId(colorModel, colorDepth); QList profiles = KoColorSpaceRegistry::instance()->profilesFor(id); Q_FOREACH(const KoColorProfile *profile, profiles) { profileNames << profile->name(); } QStringList r = profileNames.toList(); r.sort(); return r; } bool Krita::addProfile(const QString &profilePath) { KoColorSpaceEngine *iccEngine = KoColorSpaceEngineRegistry::instance()->get("icc"); return iccEngine->addProfile(profilePath); } Notifier* Krita::notifier() const { return d->notifier; } QString Krita::version() const { return KritaVersionWrapper::versionString(true); } QList Krita::views() const { QList ret; foreach(QPointer view, KisPart::instance()->views()) { ret << new View(view); } return ret; } Window *Krita::activeWindow() const { KisMainWindow *mainWindow = KisPart::instance()->currentMainwindow(); if (!mainWindow) { return 0; } return new Window(mainWindow); } QList Krita::windows() const { QList ret; foreach(QPointer mainWin, KisPart::instance()->mainWindows()) { ret << new Window(mainWin); } return ret; } QMap Krita::resources(const QString &type) const { QMap resources = QMap (); if (type.toLower() == "pattern") { KoResourceServer* server = KoResourceServerProvider::instance()->patternServer(); - Q_FOREACH (KoResource *res, server->resources()) { + Q_FOREACH (KoResourceSP res, server->resources()) { resources[res->name()] = new Resource(res); } } else if (type.toLower() == "gradient") { KoResourceServer* server = KoResourceServerProvider::instance()->gradientServer(); - Q_FOREACH (KoResource *res, server->resources()) { + Q_FOREACH (KoResourceSP res, server->resources()) { resources[res->name()] = new Resource(res); } } else if (type.toLower() == "brush") { KisBrushResourceServer* server = KisBrushServer::instance()->brushServer(); Q_FOREACH (KisBrushSP res, server->resources()) { - resources[res->name()] = new Resource(res.data()); + resources[res->name()] = new Resource(res); } } else if (type.toLower() == "preset") { KisPaintOpPresetResourceServer* server = KisResourceServerProvider::instance()->paintOpPresetServer(); Q_FOREACH (KisPaintOpPresetSP res, server->resources()) { - resources[res->name()] = new Resource(res.data()); + resources[res->name()] = new Resource(res); } } else if (type.toLower() == "palette") { KoResourceServer* server = KoResourceServerProvider::instance()->paletteServer(); - Q_FOREACH (KoResource *res, server->resources()) { + Q_FOREACH (KoResourceSP res, server->resources()) { resources[res->name()] = new Resource(res); } } else if (type.toLower() == "workspace") { KoResourceServer< KisWorkspaceResource >* server = KisResourceServerProvider::instance()->workspaceServer(); - Q_FOREACH (KoResource *res, server->resources()) { + Q_FOREACH (KoResourceSP res, server->resources()) { resources[res->name()] = new Resource(res); } } return resources; } QStringList Krita::recentDocuments() const { KConfigGroup grp = KSharedConfig::openConfig()->group(QString("RecentFiles")); QStringList keys = grp.keyList(); QStringList recentDocuments; for(int i = 0; i <= keys.filter("File").count(); i++) recentDocuments << grp.readEntry(QString("File%1").arg(i), QString("")); return recentDocuments; } Document* Krita::createDocument(int width, int height, const QString &name, const QString &colorModel, const QString &colorDepth, const QString &profile, double resolution) { KisDocument *document = KisPart::instance()->createDocument(); KisPart::instance()->addDocument(document); const KoColorSpace *cs = KoColorSpaceRegistry::instance()->colorSpace(colorModel, colorDepth, profile); Q_ASSERT(cs); QColor qc(Qt::white); qc.setAlpha(0); KoColor bgColor(qc, cs); if (!document->newImage(name, width, height, cs, bgColor, true, 1, "", double(resolution / 72) )) { return 0; } Q_ASSERT(document->image()); return new Document(document); } Document* Krita::openDocument(const QString &filename) { KisDocument *document = KisPart::instance()->createDocument(); document->setFileBatchMode(this->batchmode()); KisPart::instance()->addDocument(document); document->openUrl(QUrl::fromLocalFile(filename), KisDocument::DontAddToRecent); document->setFileBatchMode(false); return new Document(document); } Window* Krita::openWindow() { KisMainWindow *mw = KisPart::instance()->createMainWindow(); return new Window(mw); } void Krita::addExtension(Extension* extension) { d->extensions.append(extension); } QList< Extension* > Krita::extensions() { return d->extensions; } void Krita::writeSetting(const QString &group, const QString &name, const QString &value) { KConfigGroup grp = KSharedConfig::openConfig()->group(group); grp.writeEntry(name, value); } QString Krita::readSetting(const QString &group, const QString &name, const QString &defaultValue) { KConfigGroup grp = KSharedConfig::openConfig()->group(group); return grp.readEntry(name, defaultValue); } QIcon Krita::icon(QString &iconName) const { return KisIconUtils::loadIcon(iconName); } void Krita::addDockWidgetFactory(DockWidgetFactoryBase* factory) { KoDockRegistry::instance()->add(factory); } Krita* Krita::instance() { if (!s_instance) { s_instance = new Krita; } return s_instance; } /** * Scripter.fromVariant(variant) * variant is a QVariant * returns instance of QObject-subclass * * This is a helper method for PyQt because PyQt cannot cast a variant to a QObject or QWidget */ QObject *Krita::fromVariant(const QVariant& v) { if (v.canConvert< QWidget* >()) { QObject* obj = qvariant_cast< QWidget* >(v); return obj; } else if (v.canConvert< QObject* >()) { QObject* obj = qvariant_cast< QObject* >(v); return obj; } else return 0; } QString Krita::krita_i18n(const QString &text) { return i18n(text.toUtf8().constData()); } void Krita::mainWindowAdded(KisMainWindow *kisWindow) { Q_FOREACH(Extension *extension, d->extensions) { Window window(kisWindow); extension->createActions(&window); } } diff --git a/libs/libkis/Palette.cpp b/libs/libkis/Palette.cpp index 19fc2523e4..fcdeebd54c 100644 --- a/libs/libkis/Palette.cpp +++ b/libs/libkis/Palette.cpp @@ -1,155 +1,155 @@ /* * Copyright (c) 2017 Wolthera van Hövell tot Westerflier * * This program 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 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 Lesser 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 "Palette.h" #include #include #include #include #include struct Palette::Private { - KoColorSet *palette {0}; + KoColorSetSP palette {0}; }; Palette::Palette(Resource *resource): d(new Private()) { - d->palette = dynamic_cast(resource->resource()); + d->palette = resource->resource().dynamicCast(); } Palette::~Palette() { delete d; } int Palette::numberOfEntries() const { if (!d->palette) return 0; return d->palette->colorCount(); } int Palette::columnCount() { if (!d->palette) return 0; return d->palette->columnCount(); } void Palette::setColumnCount(int columns) { if (d->palette) d->palette->setColumnCount(columns); } QString Palette::comment() { if (!d->palette) return ""; return d->palette->comment(); } void Palette::setComment(QString comment) { if (!d->palette) return; return d->palette->setComment(comment); } QStringList Palette::groupNames() const { if (!d->palette) return QStringList(); return d->palette->getGroupNames(); } bool Palette::addGroup(QString name) { if (!d->palette) return false; return d->palette->addGroup(name); } bool Palette::removeGroup(QString name, bool keepColors) { if (!d->palette) return false; return d->palette->removeGroup(name, keepColors); } int Palette::colorsCountTotal() { if (!d->palette) return 0; return d->palette->colorCount(); } Swatch *Palette::colorSetEntryByIndex(int index) { if (!d->palette) return new Swatch(); int col = index % columnCount(); int row = (index - col) / columnCount(); return new Swatch(d->palette->getColorGlobal(col, row)); } Swatch *Palette::colorSetEntryFromGroup(int index, const QString &groupName) { if (!d->palette) return new Swatch(); int row = index % columnCount(); return new Swatch(d->palette->getColorGroup((index - row) / columnCount(), row, groupName)); } void Palette::addEntry(Swatch entry, QString groupName) { d->palette->add(entry.kisSwatch(), groupName); } void Palette::removeEntry(int index, const QString &/*groupName*/) { int col = index % columnCount(); int tmp = index; int row = (index - col) / columnCount(); KisSwatchGroup *groupFoundIn = Q_NULLPTR; Q_FOREACH(const QString &name, groupNames()) { KisSwatchGroup *g = d->palette->getGroup(name); tmp -= g->rowCount() * columnCount(); if (tmp < 0) { groupFoundIn = g; break; } row -= g->rowCount(); } if (!groupFoundIn) { return; } groupFoundIn->removeEntry(col, row); } bool Palette::changeGroupName(QString oldGroupName, QString newGroupName) { return d->palette->changeGroupName(oldGroupName, newGroupName); } bool Palette::moveGroup(const QString &groupName, const QString &groupNameInsertBefore) { return d->palette->moveGroup(groupName, groupNameInsertBefore); } bool Palette::save() { if (d->palette->filename().size()>0) { return d->palette->save(); } //if there's no filename the palette proly doesn't even exist... return false; } -KoColorSet *Palette::colorSet() +KoColorSetSP Palette::colorSet() { return d->palette; } diff --git a/libs/libkis/Palette.h b/libs/libkis/Palette.h index d6aa1d431d..813a677ff3 100644 --- a/libs/libkis/Palette.h +++ b/libs/libkis/Palette.h @@ -1,180 +1,180 @@ /* * Copyright (c) 2017 Wolthera van Hövell tot Westerflier * * This program 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 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 Lesser 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 LIBKIS_PALETTE_H #define LIBKIS_PALETTE_H #include #include #include "kritalibkis_export.h" #include "libkis.h" #include "Resource.h" #include "KoColorSet.h" #include class ManagedColor; /** * @brief The Palette class * Palette is a resource object that stores organised color data. * It's purpose is to allow artists to save colors and store them. * * An example for printing all the palettes and the entries: * * @code import sys from krita import * resources = Application.resources("palette") for (k, v) in resources.items(): print(k) palette = Palette(v) for x in range(palette.numberOfEntries()): entry = palette.colorSetEntryByIndex(x) c = palette.colorForEntry(entry); print(x, entry.name(), entry.id(), entry.spotColor(), c.toQString()) * @endcode */ class KRITALIBKIS_EXPORT Palette : public QObject { public: Palette(Resource *resource); ~Palette() override; /** * @brief numberOfEntries * @return */ int numberOfEntries() const; /** * @brief columnCount * @return the amount of columns this palette is set to use. */ int columnCount(); /** * @brief setColumnCount * Set the amount of columns this palette should use. */ void setColumnCount(int columns); /** * @brief comment * @return the comment or description associated with the palette. */ QString comment(); /** * @brief setComment * set the comment or description associated with the palette. * @param comment */ void setComment(QString comment); /** * @brief groupNames * @return the list of group names. This is list is in the order these groups are in the file. */ QStringList groupNames() const; /** * @brief addGroup * @param name of the new group * @return whether adding the group was successful. */ bool addGroup(QString name); /** * @brief removeGroup * @param name the name of the group to remove. * @param keepColors whether or not to delete all the colors inside, or to move them to the default group. * @return */ bool removeGroup(QString name, bool keepColors = true); /** * @brief colorsCountTotal * @return the total amount of entries in the whole group */ int colorsCountTotal(); /** * @brief colorSetEntryByIndex * get the colorsetEntry from the global index. * @param index the global index * @return the colorset entry */ Swatch *colorSetEntryByIndex(int index); /** * @brief colorSetEntryFromGroup * @param index index in the group. * @param groupName the name of the group to get the color from. * @return the colorsetentry. */ Swatch *colorSetEntryFromGroup(int index, const QString &groupName); /** * @brief addEntry * add an entry to a group. Gets appended to the end. * @param entry the entry * @param groupName the name of the group to add to. */ void addEntry(Swatch entry, QString groupName = QString()); /** * @brief removeEntry * remove the entry at @param index from the group @param groupName. */ void removeEntry(int index, const QString &groupName); /** * @brief changeGroupName * change the group name. * @param oldGroupName the old groupname to change. * @param newGroupName the new name to change it into. * @return whether successful. Reasons for failure include not knowing have oldGroupName */ bool changeGroupName(QString oldGroupName, QString newGroupName); /** * @brief moveGroup * move the group to before groupNameInsertBefore. * @param groupName group to move. * @param groupNameInsertBefore group to inset before. * @return whether successful. Reasons for failure include either group not existing. */ bool moveGroup(const QString &groupName, const QString &groupNameInsertBefore = QString()); /** * @brief save * save the palette * @return whether it was successful. */ bool save(); private: friend class PaletteView; struct Private; Private *const d; /** * @brief colorSet * @return gives qa KoColorSet object back */ - KoColorSet *colorSet(); + KoColorSetSP colorSet(); }; #endif // LIBKIS_PALETTE_H diff --git a/libs/libkis/PresetChooser.cpp b/libs/libkis/PresetChooser.cpp index d865215b96..3c1d71e645 100644 --- a/libs/libkis/PresetChooser.cpp +++ b/libs/libkis/PresetChooser.cpp @@ -1,55 +1,55 @@ /* * Copyright (c) 2017 Boudewijn Rempt * * This program 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 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 Lesser 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 "PresetChooser.h" #include #include #include "Resource.h" PresetChooser::PresetChooser(QWidget *parent) : KisPresetChooser(parent) { - connect(this, SIGNAL(resourceSelected(KoResource*)), SLOT(slotResourceSelected(KoResource*))); - connect(this, SIGNAL(resourceClicked(KoResource*)), SLOT(slotResourceClicked(KoResource*))); + connect(this, SIGNAL(resourceSelected(KoResourceSP )), SLOT(slotResourceSelected(KoResourceSP ))); + connect(this, SIGNAL(resourceClicked(KoResourceSP )), SLOT(slotResourceClicked(KoResourceSP ))); showTaggingBar(true); } void PresetChooser::setCurrentPreset(Resource *resource) { - KoResource *r = resource->resource(); + KoResourceSP r = resource->resource(); setCurrentResource(r); } Resource *PresetChooser::currentPreset() const { - KoResource *r = currentResource(); + KoResourceSP r = currentResource(); return new Resource(r); } -void PresetChooser::slotResourceSelected(KoResource *resource) +void PresetChooser::slotResourceSelected(KoResourceSP resource) { Resource *r = new Resource(resource); emit presetSelected(r); } -void PresetChooser::slotResourceClicked(KoResource *resource) +void PresetChooser::slotResourceClicked(KoResourceSP resource) { Resource *r = new Resource(resource); emit presetClicked(r); } diff --git a/libs/libkis/PresetChooser.h b/libs/libkis/PresetChooser.h index 4e835ffa55..e8dbfa1db0 100644 --- a/libs/libkis/PresetChooser.h +++ b/libs/libkis/PresetChooser.h @@ -1,75 +1,75 @@ /* * Copyright (c) 2017 Boudewijn Rempt * * This program 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 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 Lesser 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 PRESETCHOOSER_H #define PRESETCHOOSER_H #include #include #include #include "kritalibkis_export.h" #include "libkis.h" class Resource; /** * @brief The PresetChooser widget wraps the KisPresetChooser widget. * The widget provides for selecting brush presets. It has a tagging * bar and a filter field. It is not automatically synchronized with * the currently selected preset in the current Windows. */ class KRITALIBKIS_EXPORT PresetChooser : public KisPresetChooser { Q_OBJECT public: PresetChooser(QWidget *parent = 0); ~PresetChooser() override {} public Q_SLOTS: /** * Make the given preset active. */ void setCurrentPreset(Resource *resource); /** * @return a Resource wrapper around the currently selected * preset. */ Resource *currentPreset() const; Q_SIGNALS: /** * Emitted whenever a user selects the given preset. */ void presetSelected(Resource *resource); /** * Emitted whenever a user clicks on the given preset. */ void presetClicked(Resource *resource); private Q_SLOTS: - void slotResourceSelected(KoResource *resource); - void slotResourceClicked(KoResource *resource); + void slotResourceSelected(KoResourceSP resource); + void slotResourceClicked(KoResourceSP resource); }; #endif // PRESETCHOOSER_H diff --git a/libs/libkis/Resource.cpp b/libs/libkis/Resource.cpp index d773f367c7..10a5a4ef52 100644 --- a/libs/libkis/Resource.cpp +++ b/libs/libkis/Resource.cpp @@ -1,130 +1,130 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program 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 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 Lesser 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 "Resource.h" #include #include #include #include #include #include #include #include #include struct Resource::Private { - Private(KoResource *_resource) + Private(KoResourceSP _resource) : resource(_resource) {} - KoResource *resource {0}; + KoResourceSP resource {0}; }; -Resource::Resource(KoResource *resource, QObject *parent) +Resource::Resource(KoResourceSP resource, QObject *parent) : QObject(parent) , d(new Private(resource)) { } Resource::~Resource() { delete d; } bool Resource::operator==(const Resource &other) const { return (d->resource == other.d->resource); } bool Resource::operator!=(const Resource &other) const { return !(operator==(other)); } QString Resource::type() const { if (!d->resource) return QString(); - if (dynamic_cast(d->resource)) return "pattern"; - else if (dynamic_cast(d->resource)) return "gradient"; - else if (dynamic_cast(d->resource)) return "brush"; - else if (dynamic_cast(d->resource)) return "preset"; - else if (dynamic_cast(d->resource)) return "palette"; - else if (dynamic_cast(d->resource)) return "workspace"; + if (d->resource.dynamicCast()) return "pattern"; + else if (d->resource.dynamicCast()) return "gradient"; + else if (d->resource.dynamicCast()) return "brush"; + else if (d->resource.dynamicCast()) return "preset"; + else if (d->resource.dynamicCast()) return "palette"; + else if (d->resource.dynamicCast()) return "workspace"; else return ""; } QString Resource::name() const { if (!d->resource) return QString(); return d->resource->name(); } void Resource::setName(QString value) { if (!d->resource) return; d->resource->setName(value); } QString Resource::filename() const { if (!d->resource) return QString(); return d->resource->filename(); } QImage Resource::image() const { if (!d->resource) return QImage(); return d->resource->image(); } void Resource::setImage(QImage image) { if (!d->resource) return; d->resource->setImage(image); } QByteArray Resource::data() const { QByteArray ba; if (!d->resource) return ba; QBuffer buf(&ba); d->resource->saveToDevice(&buf); return ba; } bool Resource::setData(QByteArray data) { if (!d->resource) return false; QBuffer buf(&data); return d->resource->loadFromDevice(&buf); } -KoResource *Resource::resource() const +KoResourceSP Resource::resource() const { return d->resource; } diff --git a/libs/libkis/Resource.h b/libs/libkis/Resource.h index 8ed2052c11..5da4eac2bd 100644 --- a/libs/libkis/Resource.h +++ b/libs/libkis/Resource.h @@ -1,121 +1,120 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program 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 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 Lesser 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 LIBKIS_RESOURCE_H #define LIBKIS_RESOURCE_H #include #include #include "kritalibkis_export.h" #include "libkis.h" - -class KoResource; +#include /** * A Resource represents a gradient, pattern, brush tip, brush preset, palette or * workspace definition. * * @code * allPresets = Application.resources("preset") * for preset in allPresets: * print(preset.name()) * @endcode * * Resources are identified by their type, name and filename. If you want to change * the contents of a resource, you should read its data using data(), parse it and * write the changed contents back. */ class KRITALIBKIS_EXPORT Resource : public QObject { Q_OBJECT public: - explicit Resource(KoResource *resource, QObject *parent = 0); + explicit Resource(KoResourceSP resource, QObject *parent = 0); ~Resource() override; bool operator==(const Resource &other) const; bool operator!=(const Resource &other) const; public Q_SLOTS: /** * Return the type of this resource. Valid types are: *
    *
  • pattern: a raster image representing a pattern *
  • gradient: a gradient *
  • brush: a brush tip *
  • preset: a brush preset *
  • palette: a color set *
  • workspace: a workspace definition. *
*/ QString type() const; /** * The user-visible name of the resource. */ QString name() const; /** * setName changes the user-visible name of the current resource. */ void setName(QString value); /** * The filename of the resource, if present. Not all resources * are loaded from files. */ QString filename() const; /** * An image that can be used to represent the resource in the * user interface. For some resources, like patterns, the * image is identical to the resource, for others it's a mere * icon. */ QImage image() const; /** * Change the image for this resource. */ void setImage(QImage image); /** * Return the resource as a byte array. */ QByteArray data() const; /** * Change the internal data of the resource to the given byte * array. If the byte array is not valid, setData returns * false, otherwwise true. */ bool setData(QByteArray data); private: friend class PresetChooser; friend class View; friend class Palette; - KoResource *resource() const; + KoResourceSP resource() const; struct Private; const Private *const d; }; #endif // LIBKIS_RESOURCE_H diff --git a/libs/libkis/View.cpp b/libs/libkis/View.cpp index 1c3d136533..0e431d0456 100644 --- a/libs/libkis/View.cpp +++ b/libs/libkis/View.cpp @@ -1,273 +1,273 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program 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 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 Lesser 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 "View.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Document.h" #include "Canvas.h" #include "Window.h" #include "Resource.h" #include "ManagedColor.h" #include "LibKisUtils.h" struct View::Private { Private() {} QPointer view; }; View::View(KisView* view, QObject *parent) : QObject(parent) , d(new Private) { d->view = view; } View::~View() { delete d; } bool View::operator==(const View &other) const { return (d->view == other.d->view); } bool View::operator!=(const View &other) const { return !(operator==(other)); } Window* View::window() const { if (!d->view) return 0; KisMainWindow *mainwin = d->view->mainWindow(); Window *win = new Window(mainwin); return win; } Document* View::document() const { if (!d->view) return 0; Document *doc = new Document(d->view->document()); return doc; } bool View::visible() const { if (!d->view) return false; return d->view->isVisible(); } void View::setVisible() { if (!d->view) return; KisMainWindow *mainwin = d->view->mainWindow(); mainwin->setActiveView(d->view); mainwin->subWindowActivated(); } Canvas* View::canvas() const { if (!d->view) return 0; Canvas *c = new Canvas(d->view->canvasBase()); return c; } KisView *View::view() { return d->view; } void View::activateResource(Resource *resource) { if (!d->view) return; if (!resource) return; - KoResource *r= resource->resource(); + KoResourceSP r = resource->resource(); if (!r) return; - if (dynamic_cast(r)) { + if (r.dynamicCast()) { QVariant v; - v.setValue(static_cast(r)); + v.setValue(r); d->view->canvasBase()->resourceManager()->setResource(KisCanvasResourceProvider::CurrentPattern, v); } - else if (dynamic_cast(r)) { + else if (r.dynamicCast()) { QVariant v; - v.setValue(static_cast(r)); + v.setValue(r); d->view->canvasBase()->resourceManager()->setResource(KisCanvasResourceProvider::CurrentGradient, v); } - else if (dynamic_cast(r)) { + else if (r.dynamicCast()) { d->view->viewManager()->paintOpBox()->resourceSelected(r); } } ManagedColor *View::foregroundColor() const { if (!d->view) return 0; return new ManagedColor(d->view->resourceProvider()->fgColor()); } void View::setForeGroundColor(ManagedColor *color) { if (!d->view) return; d->view->resourceProvider()->setFGColor(color->color()); } ManagedColor *View::backgroundColor() const { if (!d->view) return 0; return new ManagedColor(d->view->resourceProvider()->bgColor()); } void View::setBackGroundColor(ManagedColor *color) { if (!d->view) return; d->view->resourceProvider()->setBGColor(color->color()); } Resource *View::currentBrushPreset() const { if (!d->view) return 0; - return new Resource(d->view->resourceProvider()->currentPreset().data()); + return new Resource(d->view->resourceProvider()->currentPreset()); } void View::setCurrentBrushPreset(Resource *resource) { activateResource(resource); } Resource *View::currentPattern() const { if (!d->view) return 0; return new Resource(d->view->resourceProvider()->currentPattern()); } void View::setCurrentPattern(Resource *resource) { activateResource(resource); } Resource *View::currentGradient() const { if (!d->view) return 0; return new Resource(d->view->resourceProvider()->currentGradient()); } void View::setCurrentGradient(Resource *resource) { activateResource(resource); } QString View::currentBlendingMode() const { if (!d->view) return ""; return d->view->resourceProvider()->currentCompositeOp(); } void View::setCurrentBlendingMode(const QString &blendingMode) { if (!d->view) return; d->view->resourceProvider()->setCurrentCompositeOp(blendingMode); } float View::HDRExposure() const { if (!d->view) return 0.0; return d->view->resourceProvider()->HDRExposure(); } void View::setHDRExposure(float exposure) { if (!d->view) return; d->view->resourceProvider()->setHDRExposure(exposure); } float View::HDRGamma() const { if (!d->view) return 0.0; return d->view->resourceProvider()->HDRGamma(); } void View::setHDRGamma(float gamma) { if (!d->view) return; d->view->resourceProvider()->setHDRGamma(gamma); } qreal View::paintingOpacity() const { if (!d->view) return 0.0; return d->view->resourceProvider()->opacity(); } void View::setPaintingOpacity(qreal opacity) { if (!d->view) return; d->view->resourceProvider()->setOpacity(opacity); } qreal View::brushSize() const { if (!d->view) return 0.0; return d->view->resourceProvider()->size(); } void View::setBrushSize(qreal brushSize) { if (!d->view) return; d->view->resourceProvider()->setSize(brushSize); } qreal View::paintingFlow() const { if (!d->view) return 0.0; return d->view->resourceProvider()->flow(); } void View::setPaintingFlow(qreal flow) { if (!d->view) return; d->view->resourceProvider()->setFlow(flow); } QList View::selectedNodes() const { if (!d->view) return QList(); if (!d->view->viewManager()) return QList(); if (!d->view->viewManager()->nodeManager()) return QList(); KisNodeList selectedNodes = d->view->viewManager()->nodeManager()->selectedNodes(); return LibKisUtils::createNodeList(selectedNodes, d->view->image()); } diff --git a/libs/libqml/plugins/kritasketchplugin/models/PaletteColorsModel.cpp b/libs/libqml/plugins/kritasketchplugin/models/PaletteColorsModel.cpp index eb0d1f08e1..797219bd4b 100644 --- a/libs/libqml/plugins/kritasketchplugin/models/PaletteColorsModel.cpp +++ b/libs/libqml/plugins/kritasketchplugin/models/PaletteColorsModel.cpp @@ -1,151 +1,155 @@ /* This file is part of the KDE project * Copyright (C) 2012 Dan Leinir Turthra Jensen * * 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 "PaletteColorsModel.h" #include #include #include class PaletteColorsModel::Private { public: Private() : colorSet(0) , view(0) {} - KoColorSet* colorSet; + KoColorSetSP colorSet; KisViewManager* view; }; PaletteColorsModel::PaletteColorsModel(QObject *parent) : QAbstractListModel(parent) , d(new Private) { } PaletteColorsModel::~PaletteColorsModel() { delete d; } QHash PaletteColorsModel::roleNames() const { QHash roles; roles[ImageRole] = "image"; roles[TextRole] = "text"; return roles; } int PaletteColorsModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) return 0; if (!d->colorSet) return 0; return d->colorSet->colorCount(); } QVariant PaletteColorsModel::data(const QModelIndex &/*index*/, int /*role*/) const { QVariant result; /* QColor color; if (index.isValid() && d->colorSet) { switch(role) { case ImageRole: color = d->colorSet->getColorGlobal(index.row(), index.column()).color().toQColor(); result = QString("image://color/%1,%2,%3,%4").arg(color.redF()).arg(color.greenF()).arg(color.blueF()).arg(color.alphaF()); break; case TextRole: result = d->colorSet->getColorGlobal(index.row(), index.column()).name(); break; default: break; } } */ return result; } QVariant PaletteColorsModel::headerData(int section, Qt::Orientation orientation, int role) const { Q_UNUSED(orientation); QVariant result; if (section == 0) { switch(role) { case ImageRole: result = QString("Thumbnail"); break; case TextRole: result = QString("Name"); break; default: break; } } return result; } void PaletteColorsModel::setColorSet(QObject *newColorSet) { - d->colorSet = qobject_cast(newColorSet); + // XXX SharedPtr We need to wrap KoColorSet + + //d->colorSet = qobject_cast(newColorSet); beginResetModel(); endResetModel(); emit colorSetChanged(); } QObject* PaletteColorsModel::colorSet() const { - return d->colorSet; + // XXX SharedPtr We need to wrap KoColorSet + // return d->colorSet; + return 0; } QObject* PaletteColorsModel::view() const { return d->view; } void PaletteColorsModel::setView(QObject* newView) { d->view = qobject_cast( newView ); emit viewChanged(); } void PaletteColorsModel::activateColor(int index, bool /*setBackgroundColor*/) { if ( !d->view ) return; if (index >= 0 && index < (int)d->colorSet->colorCount()) { /* if (setBackgroundColor) d->view->resourceProvider()->setBGColor(d->colorSet->getColorGlobal(index).color()); else d->view->resourceProvider()->setFGColor( d->colorSet->getColorGlobal(index).color()); emit colorChanged(d->colorSet->getColorGlobal(index).color().toQColor(), setBackgroundColor); */ } } diff --git a/libs/libqml/plugins/kritasketchplugin/models/PaletteColorsModel.h b/libs/libqml/plugins/kritasketchplugin/models/PaletteColorsModel.h index cfd53e5504..71603be0cf 100644 --- a/libs/libqml/plugins/kritasketchplugin/models/PaletteColorsModel.h +++ b/libs/libqml/plugins/kritasketchplugin/models/PaletteColorsModel.h @@ -1,61 +1,62 @@ /* This file is part of the KDE project * Copyright (C) 2012 Dan Leinir Turthra Jensen * * 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 PALETTECOLORSMODEL_H #define PALETTECOLORSMODEL_H #include #include +#include class PaletteColorsModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(QObject* colorSet READ colorSet WRITE setColorSet NOTIFY colorSetChanged) Q_PROPERTY(QObject* view READ view WRITE setView NOTIFY viewChanged) public: enum PaletteColorsRoles { ImageRole = Qt::UserRole + 1, TextRole }; explicit PaletteColorsModel(QObject *parent = 0); virtual ~PaletteColorsModel(); QHash roleNames() const; virtual int rowCount(const QModelIndex &parent) const; virtual QVariant data(const QModelIndex &index, int role) const; virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; QObject* view() const; void setView(QObject* newView); QObject* colorSet() const; void setColorSet(QObject* newColorSet); Q_SIGNALS: void colorChanged(QColor newColor, bool backgroundChanged); void colorSetChanged(); void viewChanged(); public Q_SLOTS: void activateColor(int index, bool setBackgroundColor); private: class Private; Private* d; }; #endif // PALETTECOLORSMODEL_H diff --git a/libs/libqml/plugins/kritasketchplugin/models/PaletteModel.cpp b/libs/libqml/plugins/kritasketchplugin/models/PaletteModel.cpp index 1c8ee8e3de..de9c224ba4 100644 --- a/libs/libqml/plugins/kritasketchplugin/models/PaletteModel.cpp +++ b/libs/libqml/plugins/kritasketchplugin/models/PaletteModel.cpp @@ -1,121 +1,122 @@ /* This file is part of the KDE project * Copyright (C) 2012 Dan Leinir Turthra Jensen * * 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 "PaletteModel.h" #include #include #include #include class PaletteModel::Private { public: Private(QObject* q) : currentSet(0) { KoResourceServer* rServer = KoResourceServerProvider::instance()->paletteServer(); serverAdaptor = new KoResourceServerAdapter(rServer, q); serverAdaptor->connectToResourceServer(); } KoResourceServerAdapter* serverAdaptor; - KoColorSet* currentSet; + KoColorSetSP currentSet; }; PaletteModel::PaletteModel(QObject *parent) : QAbstractListModel(parent) , d(new Private(this)) { } PaletteModel::~PaletteModel() { delete d; } QHash PaletteModel::roleNames() const { QHash roles; roles[ImageRole] = "image"; roles[TextRole] = "text"; return roles; } int PaletteModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) return 0; return d->serverAdaptor->resources().count(); } QVariant PaletteModel::data(const QModelIndex &index, int role) const { QVariant result; if (index.isValid()) { switch(role) { case ImageRole: result = "../images/help-about.png"; break; case TextRole: result = d->serverAdaptor->resources().at(index.row())->name(); break; default: break; } } return result; } QVariant PaletteModel::headerData(int section, Qt::Orientation orientation, int role) const { Q_UNUSED(orientation); QVariant result; if (section == 0) { switch(role) { case ImageRole: result = QString("Thumbnail"); break; case TextRole: result = QString("Name"); break; default: break; } } return result; } void PaletteModel::itemActivated(int index) { - QList resources = d->serverAdaptor->resources(); + QList resources = d->serverAdaptor->resources(); if (index >= 0 && index < resources.count()) { - d->currentSet = dynamic_cast(resources.at(index)); + d->currentSet = resources.at(index).dynamicCast(); emit colorSetChanged(); } } QObject* PaletteModel::colorSet() const { - return d->currentSet; + // XXX SharedPtr We need to wrap KoColorSet + return 0;// d->currentSet; } diff --git a/libs/libqml/plugins/kritasketchplugin/models/PresetModel.cpp b/libs/libqml/plugins/kritasketchplugin/models/PresetModel.cpp index fdbedcec42..2216e16390 100644 --- a/libs/libqml/plugins/kritasketchplugin/models/PresetModel.cpp +++ b/libs/libqml/plugins/kritasketchplugin/models/PresetModel.cpp @@ -1,217 +1,217 @@ /* This file is part of the KDE project * Copyright (C) 2012 Dan Leinir Turthra Jensen * * 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 "PresetModel.h" #include #include #include #include #include #include #include #include #include #include #include class PresetModel::Private { public: Private() : view(0) { rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); } KisPaintOpPresetResourceServer * rserver; QString currentPreset; KisViewManager* view; KisPaintOpPresetSP defaultPreset(const KoID& paintOp) { QString defaultName = paintOp.id() + ".kpp"; QString path = KoResourcePaths::findResource("kis_defaultpresets", defaultName); - KisPaintOpPresetSP preset = new KisPaintOpPreset(path); + KisPaintOpPresetSP preset(new KisPaintOpPreset(path)); if (!preset->load()) preset = KisPaintOpRegistry::instance()->defaultPreset(paintOp); Q_ASSERT(preset); Q_ASSERT(preset->valid()); return preset; } void setCurrentPaintop(const KoID& paintop, KisPaintOpPresetSP preset) { preset = (!preset) ? defaultPreset(paintop) : preset; Q_ASSERT(preset && preset->settings()); // handle the settings and expose it through a a simple QObject property //m_optionWidget->setConfiguration(preset->settings()); #if 0 preset->settings()->setNode(view->resourceProvider()->currentNode()); #endif view->resourceProvider()->setPaintOpPreset(preset); } }; PresetModel::PresetModel(QObject *parent) : QAbstractListModel(parent) , d(new Private) { } PresetModel::~PresetModel() { delete d; } QHash PresetModel::roleNames() const { QHash roles; roles[ImageRole] = "image"; roles[TextRole] = "text"; roles[NameRole] = "name"; return roles; } int PresetModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) return 0; return d->rserver->resources().count(); } QVariant PresetModel::data(const QModelIndex &index, int role) const { QVariant result; if (index.isValid()) { switch(role) { case ImageRole: result = QString("image://presetthumb/%1").arg(index.row()); break; case TextRole: result = d->rserver->resources().at(index.row())->name().replace(QLatin1String("_"), QLatin1String(" ")); break; case NameRole: result = d->rserver->resources().at(index.row())->name(); break; default: result = ""; break; } } return result; } QVariant PresetModel::headerData(int section, Qt::Orientation orientation, int role) const { Q_UNUSED(orientation); QVariant result; if (section == 0) { switch(role) { case ImageRole: result = QString("Thumbnail"); break; case TextRole: result = QString("Name"); break; default: result = ""; break; } } return result; } QObject* PresetModel::view() const { return d->view; } void PresetModel::setView(QObject* newView) { d->view = qobject_cast( newView ); if (d->view && d->view->canvasBase()) { connect(d->view->canvasBase()->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)), this, SLOT(resourceChanged(int,QVariant))); } emit viewChanged(); } QString PresetModel::currentPreset() const { return d->currentPreset; } void PresetModel::setCurrentPreset(QString presetName) { activatePreset(nameToIndex(presetName)); // not emitting here, as that happens when the resource changes... this is more // a polite request than an actual setter, due to the nature of the resource system. } int PresetModel::nameToIndex(QString presetName) const { int index = 0; QList resources = d->rserver->resources(); for(int i = 0; i < resources.count(); ++i) { if (resources.at(i)->name() == presetName || resources.at(i)->name().replace(QLatin1String("_"), QLatin1String(" ")) == presetName) { index = i; break; } } return index; } void PresetModel::activatePreset(int index) { if ( !d->view ) return; QList resources = d->rserver->resources(); if (index >= 0 && index < resources.count()) { KisPaintOpPresetSP preset = resources.at( index ); d->setCurrentPaintop(preset->paintOp(), preset); } } void PresetModel::resourceChanged(int /*key*/, const QVariant& /*v*/) { if (d->view) { KisPaintOpPresetSP preset = d->view->canvasBase()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value(); if (preset && d->currentPreset != preset->name()) { d->currentPreset = preset->name(); emit currentPresetChanged(); } } } diff --git a/libs/pigment/resources/KoAbstractGradient.h b/libs/pigment/resources/KoAbstractGradient.h index b6dba8159f..0a810c9e4c 100644 --- a/libs/pigment/resources/KoAbstractGradient.h +++ b/libs/pigment/resources/KoAbstractGradient.h @@ -1,93 +1,95 @@ /* Copyright (c) 2007 Sven Langkamp This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef KOABSTRACTGRADIENT_H #define KOABSTRACTGRADIENT_H #include #include #include "KoColorSpace.h" #include #include class KoAbstractGradient; typedef QSharedPointer KoAbstractGradientSP; class KoColor; /** * KoAbstractGradient is the base class of all gradient resources */ class KRITAPIGMENT_EXPORT KoAbstractGradient : public KoResource { public: explicit KoAbstractGradient(const QString &filename); ~KoAbstractGradient() override; - virtual KoAbstractGradient* clone() const = 0; + virtual KoAbstractGradientSP clone() const = 0; bool load() override { return false; } bool loadFromDevice(QIODevice *) override { return false; } bool save() override { return false; } bool saveToDevice(QIODevice*) const override { return false; } /** * Creates a QGradient from the gradient. * The resulting QGradient might differ from original gradient */ virtual QGradient* toQGradient() const { return new QGradient(); } /// gets the color at position 0 <= t <= 1 virtual void colorAt(KoColor&, qreal t) const; void setColorSpace(KoColorSpace* colorSpace); const KoColorSpace * colorSpace() const; void setSpread(QGradient::Spread spreadMethod); QGradient::Spread spread() const; void setType(QGradient::Type repeatType); QGradient::Type type() const; void updatePreview(); QImage generatePreview(int width, int height) const; KoAbstractGradient(const KoAbstractGradient &rhs); private: struct Private; Private* const d; }; Q_DECLARE_METATYPE(KoAbstractGradient*) +Q_DECLARE_METATYPE(QSharedPointer) + #endif // KOABSTRACTGRADIENT_H diff --git a/libs/pigment/resources/KoColorSet.cpp b/libs/pigment/resources/KoColorSet.cpp index d571ac7abd..14911a8f99 100644 --- a/libs/pigment/resources/KoColorSet.cpp +++ b/libs/pigment/resources/KoColorSet.cpp @@ -1,1608 +1,1607 @@ /* This file is part of the KDE project Copyright (c) 2005 Boudewijn Rempt Copyright (c) 2016 L. E. Segovia 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 #include #include #include #include #include #include #include #include #include // qFromLittleEndian #include #include #include #include #include #include #include #include #include "KisSwatch.h" #include "KoColorSet.h" #include "KoColorSet_p.h" const QString KoColorSet::GLOBAL_GROUP_NAME = QString(); const QString KoColorSet::KPL_VERSION_ATTR = "version"; const QString KoColorSet::KPL_GROUP_ROW_COUNT_ATTR = "rows"; const QString KoColorSet::KPL_PALETTE_COLUMN_COUNT_ATTR = "columns"; const QString KoColorSet::KPL_PALETTE_NAME_ATTR = "name"; const QString KoColorSet::KPL_PALETTE_COMMENT_ATTR = "comment"; const QString KoColorSet::KPL_PALETTE_FILENAME_ATTR = "filename"; const QString KoColorSet::KPL_PALETTE_READONLY_ATTR = "readonly"; const QString KoColorSet::KPL_COLOR_MODEL_ID_ATTR = "colorModelId"; const QString KoColorSet::KPL_COLOR_DEPTH_ID_ATTR = "colorDepthId"; const QString KoColorSet::KPL_GROUP_NAME_ATTR = "name"; const QString KoColorSet::KPL_SWATCH_ROW_ATTR = "row"; const QString KoColorSet::KPL_SWATCH_COL_ATTR = "column"; const QString KoColorSet::KPL_SWATCH_NAME_ATTR = "name"; const QString KoColorSet::KPL_SWATCH_ID_ATTR = "id"; const QString KoColorSet::KPL_SWATCH_SPOT_ATTR = "spot"; const QString KoColorSet::KPL_SWATCH_BITDEPTH_ATTR = "bitdepth"; const QString KoColorSet::KPL_PALETTE_PROFILE_TAG = "Profile"; const QString KoColorSet::KPL_SWATCH_POS_TAG = "Position"; const QString KoColorSet::KPL_SWATCH_TAG = "ColorSetEntry"; const QString KoColorSet::KPL_GROUP_TAG = "Group"; const QString KoColorSet::KPL_PALETTE_TAG = "ColorSet"; KoColorSet::KoColorSet(const QString& filename) : KoResource(filename) - , d(new Private(this)) + , d(new Private(QSharedPointer(this))) { if (!filename.isEmpty()) { QFileInfo f(filename); setIsEditable(f.isWritable()); } } /// Create an copied palette KoColorSet::KoColorSet(const KoColorSet& rhs) - : QObject(Q_NULLPTR) - , KoResource(rhs) - , d(new Private(this)) + : KoResource(rhs) + , d(new Private(QSharedPointer(this))) { d->paletteType = rhs.d->paletteType; d->data = rhs.d->data; d->comment = rhs.d->comment; d->groupNames = rhs.d->groupNames; d->groups = rhs.d->groups; d->isGlobal = rhs.d->isGlobal; d->isEditable = rhs.d->isEditable; } KoColorSet::~KoColorSet() { } bool KoColorSet::load() { QFile file(filename()); if (file.size() == 0) return false; if (!file.open(QIODevice::ReadOnly)) { warnPigment << "Can't open file " << filename(); return false; } bool res = loadFromDevice(&file); file.close(); if (!QFileInfo(filename()).isWritable()) { setIsEditable(false); } return res; } bool KoColorSet::loadFromDevice(QIODevice *dev) { if (!dev->isOpen()) dev->open(QIODevice::ReadOnly); d->data = dev->readAll(); Q_ASSERT(d->data.size() != 0); return d->init(); } bool KoColorSet::save() { if (d->isGlobal) { // save to resource dir QFile file(filename()); if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { return false; } saveToDevice(&file); file.close(); return true; } else { return true; // palette is not global, but still indicate that it's saved } } bool KoColorSet::saveToDevice(QIODevice *dev) const { bool res; switch(d->paletteType) { case GPL: res = d->saveGpl(dev); break; default: res = d->saveKpl(dev); } if (res) { KoResource::saveToDevice(dev); } return res; } QByteArray KoColorSet::toByteArray() const { QBuffer s; s.open(QIODevice::WriteOnly); if (!saveToDevice(&s)) { warnPigment << "saving palette failed:" << name(); return QByteArray(); } s.close(); s.open(QIODevice::ReadOnly); QByteArray res = s.readAll(); s.close(); return res; } bool KoColorSet::fromByteArray(QByteArray &data) { QBuffer buf(&data); buf.open(QIODevice::ReadOnly); return loadFromDevice(&buf); } KoColorSet::PaletteType KoColorSet::paletteType() const { return d->paletteType; } void KoColorSet::setPaletteType(PaletteType paletteType) { d->paletteType = paletteType; QString suffix; switch(d->paletteType) { case GPL: suffix = ".gpl"; break; case ACT: suffix = ".act"; break; case RIFF_PAL: case PSP_PAL: suffix = ".pal"; break; case ACO: suffix = ".aco"; break; case XML: suffix = ".xml"; break; case KPL: suffix = ".kpl"; break; case SBZ: suffix = ".sbz"; break; default: suffix = defaultFileExtension(); } QStringList fileName = filename().split("."); fileName.last() = suffix.replace(".", ""); setFilename(fileName.join(".")); } quint32 KoColorSet::colorCount() const { int colorCount = d->groups[GLOBAL_GROUP_NAME].colorCount(); for (KisSwatchGroup &g : d->groups.values()) { colorCount += g.colorCount(); } return colorCount; } void KoColorSet::add(const KisSwatch &c, const QString &groupName) { KisSwatchGroup &modifiedGroup = d->groups.contains(groupName) ? d->groups[groupName] : d->global(); modifiedGroup.addEntry(c); } void KoColorSet::setEntry(const KisSwatch &e, int x, int y, const QString &groupName) { KisSwatchGroup &modifiedGroup = d->groups.contains(groupName) ? d->groups[groupName] : d->global(); modifiedGroup.setEntry(e, x, y); } void KoColorSet::clear() { d->groups.clear(); d->groupNames.clear(); d->groups[GLOBAL_GROUP_NAME] = KisSwatchGroup(); d->groupNames.append(GLOBAL_GROUP_NAME); } KisSwatch KoColorSet::getColorGlobal(quint32 x, quint32 y) const { int yInGroup = y; QString nameGroupFoundIn; for (const QString &groupName : d->groupNames) { if (yInGroup < d->groups[groupName].rowCount()) { nameGroupFoundIn = groupName; break; } else { yInGroup -= d->groups[groupName].rowCount(); } } const KisSwatchGroup &groupFoundIn = nameGroupFoundIn == GLOBAL_GROUP_NAME ? d->global() : d->groups[nameGroupFoundIn]; Q_ASSERT(groupFoundIn.checkEntry(x, yInGroup)); return groupFoundIn.getEntry(x, yInGroup); } KisSwatch KoColorSet::getColorGroup(quint32 x, quint32 y, QString groupName) { KisSwatch e; const KisSwatchGroup &sourceGroup = groupName == QString() ? d->global() : d->groups[groupName]; if (sourceGroup.checkEntry(x, y)) { e = sourceGroup.getEntry(x, y); } return e; } QStringList KoColorSet::getGroupNames() { if (d->groupNames.size() != d->groups.size()) { warnPigment << "mismatch between groups and the groupnames list."; return QStringList(d->groups.keys()); } return d->groupNames; } bool KoColorSet::changeGroupName(const QString &oldGroupName, const QString &newGroupName) { if (!d->groups.contains(oldGroupName)) { return false; } if (oldGroupName == newGroupName) { return true; } d->groups[newGroupName] = d->groups[oldGroupName]; d->groups.remove(oldGroupName); d->groups[newGroupName].setName(newGroupName); //rename the string in the stringlist; int index = d->groupNames.indexOf(oldGroupName); d->groupNames.replace(index, newGroupName); return true; } void KoColorSet::setColumnCount(int columns) { d->groups[GLOBAL_GROUP_NAME].setColumnCount(columns); for (KisSwatchGroup &g : d->groups.values()) { g.setColumnCount(columns); } } int KoColorSet::columnCount() const { return d->groups[GLOBAL_GROUP_NAME].columnCount(); } QString KoColorSet::comment() { return d->comment; } void KoColorSet::setComment(QString comment) { d->comment = comment; } bool KoColorSet::addGroup(const QString &groupName) { if (d->groups.contains(groupName) || d->groupNames.contains(groupName)) { return false; } d->groupNames.append(groupName); d->groups[groupName] = KisSwatchGroup(); d->groups[groupName].setName(groupName); return true; } bool KoColorSet::moveGroup(const QString &groupName, const QString &groupNameInsertBefore) { if (d->groupNames.contains(groupName)==false || d->groupNames.contains(groupNameInsertBefore)==false) { return false; } if (groupNameInsertBefore != GLOBAL_GROUP_NAME && groupName != GLOBAL_GROUP_NAME) { d->groupNames.removeAt(d->groupNames.indexOf(groupName)); int index = d->groupNames.indexOf(groupNameInsertBefore); d->groupNames.insert(index, groupName); } return true; } bool KoColorSet::removeGroup(const QString &groupName, bool keepColors) { if (!d->groups.contains(groupName)) { return false; } if (groupName == GLOBAL_GROUP_NAME) { return false; } if (keepColors) { // put all colors directly below global int startingRow = d->groups[GLOBAL_GROUP_NAME].rowCount(); for (const KisSwatchGroup::SwatchInfo &info : d->groups[groupName].infoList()) { d->groups[GLOBAL_GROUP_NAME].setEntry(info.swatch, info.column, info.row + startingRow); } } d->groupNames.removeAt(d->groupNames.indexOf(groupName)); d->groups.remove(groupName); return true; } QString KoColorSet::defaultFileExtension() const { return QString(".kpl"); } int KoColorSet::rowCount() const { int res = 0; for (const QString &name : d->groupNames) { res += d->groups[name].rowCount(); } return res; } KisSwatchGroup *KoColorSet::getGroup(const QString &name) { if (!d->groups.contains(name)) { return Q_NULLPTR; } return &(d->groups[name]); } KisSwatchGroup *KoColorSet::getGlobalGroup() { return getGroup(GLOBAL_GROUP_NAME); } bool KoColorSet::isGlobal() const { return d->isGlobal; } void KoColorSet::setIsGlobal(bool isGlobal) { d->isGlobal = isGlobal; } bool KoColorSet::isEditable() const { return d->isEditable; } void KoColorSet::setIsEditable(bool isEditable) { d->isEditable = isEditable; } KisSwatchGroup::SwatchInfo KoColorSet::getClosestColorInfo(KoColor compare, bool useGivenColorSpace) { KisSwatchGroup::SwatchInfo res; quint8 highestPercentage = 0; quint8 testPercentage = 0; for (const QString &groupName : getGroupNames()) { KisSwatchGroup *group = getGroup(groupName); for (const KisSwatchGroup::SwatchInfo &currInfo : group->infoList()) { KoColor color = currInfo.swatch.color(); if (useGivenColorSpace == true && compare.colorSpace() != color.colorSpace()) { color.convertTo(compare.colorSpace()); } else if (compare.colorSpace() != color.colorSpace()) { compare.convertTo(color.colorSpace()); } testPercentage = (255 - compare.colorSpace()->difference(compare.data(), color.data())); if (testPercentage > highestPercentage) { highestPercentage = testPercentage; res = currInfo; } } } return res; } /********************************KoColorSet::Private**************************/ -KoColorSet::Private::Private(KoColorSet *a_colorSet) +KoColorSet::Private::Private(KoColorSetSP a_colorSet) : colorSet(a_colorSet) , isGlobal(true) , isEditable(false) { groups[KoColorSet::GLOBAL_GROUP_NAME] = KisSwatchGroup(); groupNames.append(KoColorSet::GLOBAL_GROUP_NAME); } KoColorSet::PaletteType KoColorSet::Private::detectFormat(const QString &fileName, const QByteArray &ba) { QFileInfo fi(fileName); // .pal if (ba.startsWith("RIFF") && ba.indexOf("PAL data", 8)) { return KoColorSet::RIFF_PAL; } // .gpl else if (ba.startsWith("GIMP Palette")) { return KoColorSet::GPL; } // .pal else if (ba.startsWith("JASC-PAL")) { return KoColorSet::PSP_PAL; } else if (fi.suffix().toLower() == "aco") { return KoColorSet::ACO; } else if (fi.suffix().toLower() == "act") { return KoColorSet::ACT; } else if (fi.suffix().toLower() == "xml") { return KoColorSet::XML; } else if (fi.suffix().toLower() == "kpl") { return KoColorSet::KPL; } else if (fi.suffix().toLower() == "sbz") { return KoColorSet::SBZ; } return KoColorSet::UNKNOWN; } -void KoColorSet::Private::scribusParseColor(KoColorSet *set, QXmlStreamReader *xml) +void KoColorSet::Private::scribusParseColor(KoColorSetSP set, QXmlStreamReader *xml) { KisSwatch colorEntry; // It's a color, retrieve it QXmlStreamAttributes colorProperties = xml->attributes(); QStringRef colorName = colorProperties.value("NAME"); colorEntry.setName(colorName.isEmpty() || colorName.isNull() ? i18n("Untitled") : colorName.toString()); // RGB or CMYK? if (colorProperties.hasAttribute("RGB")) { dbgPigment << "Color " << colorProperties.value("NAME") << ", RGB " << colorProperties.value("RGB"); KoColor currentColor(KoColorSpaceRegistry::instance()->rgb8()); QStringRef colorValue = colorProperties.value("RGB"); if (colorValue.length() != 7 && colorValue.at(0) != '#') { // Color is a hexadecimal number xml->raiseError("Invalid rgb8 color (malformed): " + colorValue); return; } else { bool rgbOk; quint32 rgb = colorValue.mid(1).toUInt(&rgbOk, 16); if (!rgbOk) { xml->raiseError("Invalid rgb8 color (unable to convert): " + colorValue); return; } quint8 r = rgb >> 16 & 0xff; quint8 g = rgb >> 8 & 0xff; quint8 b = rgb & 0xff; dbgPigment << "Color parsed: "<< r << g << b; currentColor.data()[0] = r; currentColor.data()[1] = g; currentColor.data()[2] = b; currentColor.setOpacity(OPACITY_OPAQUE_U8); colorEntry.setColor(currentColor); set->add(colorEntry); while(xml->readNextStartElement()) { //ignore - these are all unknown or the /> element tag xml->skipCurrentElement(); } return; } } else if (colorProperties.hasAttribute("CMYK")) { dbgPigment << "Color " << colorProperties.value("NAME") << ", CMYK " << colorProperties.value("CMYK"); KoColor currentColor(KoColorSpaceRegistry::instance()->colorSpace(CMYKAColorModelID.id(), Integer8BitsColorDepthID.id(), QString())); QStringRef colorValue = colorProperties.value("CMYK"); if (colorValue.length() != 9 && colorValue.at(0) != '#') { // Color is a hexadecimal number xml->raiseError("Invalid cmyk color (malformed): " % colorValue); return; } else { bool cmykOk; quint32 cmyk = colorValue.mid(1).toUInt(&cmykOk, 16); // cmyk uses the full 32 bits if (!cmykOk) { xml->raiseError("Invalid cmyk color (unable to convert): " % colorValue); return; } quint8 c = cmyk >> 24 & 0xff; quint8 m = cmyk >> 16 & 0xff; quint8 y = cmyk >> 8 & 0xff; quint8 k = cmyk & 0xff; dbgPigment << "Color parsed: "<< c << m << y << k; currentColor.data()[0] = c; currentColor.data()[1] = m; currentColor.data()[2] = y; currentColor.data()[3] = k; currentColor.setOpacity(OPACITY_OPAQUE_U8); colorEntry.setColor(currentColor); set->add(colorEntry); while(xml->readNextStartElement()) { //ignore - these are all unknown or the /> element tag xml->skipCurrentElement(); } return; } } else { xml->raiseError("Unknown color space for color " + colorEntry.name()); } } -bool KoColorSet::Private::loadScribusXmlPalette(KoColorSet *set, QXmlStreamReader *xml) +bool KoColorSet::Private::loadScribusXmlPalette(KoColorSetSP set, QXmlStreamReader *xml) { //1. Get name QXmlStreamAttributes paletteProperties = xml->attributes(); QStringRef paletteName = paletteProperties.value("Name"); dbgPigment << "Processed name of palette:" << paletteName; set->setName(paletteName.toString()); //2. Inside the SCRIBUSCOLORS, there are lots of colors. Retrieve them while(xml->readNextStartElement()) { QStringRef currentElement = xml->name(); if(QStringRef::compare(currentElement, "COLOR", Qt::CaseInsensitive) == 0) { scribusParseColor(set, xml); } else { xml->skipCurrentElement(); } } if(xml->hasError()) { return false; } return true; } quint16 KoColorSet::Private::readShort(QIODevice *io) { quint16 val; quint64 read = io->read((char*)&val, 2); if (read != 2) return false; return qFromBigEndian(val); } bool KoColorSet::Private::init() { // just in case this is a reload (eg by KoEditColorSetDialog), groupNames.clear(); groups.clear(); groupNames.append(KoColorSet::GLOBAL_GROUP_NAME); groups[KoColorSet::GLOBAL_GROUP_NAME] = KisSwatchGroup(); if (colorSet->filename().isNull()) { warnPigment << "Cannot load palette" << colorSet->name() << "there is no filename set"; return false; } if (data.isNull()) { QFile file(colorSet->filename()); if (file.size() == 0) { warnPigment << "Cannot load palette" << colorSet->name() << "there is no data available"; return false; } file.open(QIODevice::ReadOnly); data = file.readAll(); file.close(); } bool res = false; paletteType = detectFormat(colorSet->filename(), data); switch(paletteType) { case GPL: res = loadGpl(); break; case ACT: res = loadAct(); break; case RIFF_PAL: res = loadRiff(); break; case PSP_PAL: res = loadPsp(); break; case ACO: res = loadAco(); break; case XML: res = loadXml(); break; case KPL: res = loadKpl(); break; case SBZ: res = loadSbz(); break; default: res = false; } colorSet->setValid(res); QImage img(global().columnCount() * 4, global().rowCount() * 4, QImage::Format_ARGB32); QPainter gc(&img); gc.fillRect(img.rect(), Qt::darkGray); for (const KisSwatchGroup::SwatchInfo &info : global().infoList()) { QColor c = info.swatch.color().toQColor(); gc.fillRect(info.column * 4, info.row * 4, 4, 4, c); } colorSet->setImage(img); colorSet->setValid(res); data.clear(); return res; } bool KoColorSet::Private::saveGpl(QIODevice *dev) const { Q_ASSERT(dev->isOpen()); Q_ASSERT(dev->isWritable()); QTextStream stream(dev); stream << "GIMP Palette\nName: " << colorSet->name() << "\nColumns: " << colorSet->columnCount() << "\n#\n"; /* * Qt doesn't provide an interface to get a const reference to a QHash, that is * the underlying data structure of groups. Therefore, directly use * groups[KoColorSet::GLOBAL_GROUP_NAME] so that saveGpl can stay const */ for (int y = 0; y < groups[KoColorSet::GLOBAL_GROUP_NAME].rowCount(); y++) { for (int x = 0; x < colorSet->columnCount(); x++) { if (!groups[KoColorSet::GLOBAL_GROUP_NAME].checkEntry(x, y)) { continue; } const KisSwatch& entry = groups[KoColorSet::GLOBAL_GROUP_NAME].getEntry(x, y); QColor c = entry.color().toQColor(); stream << c.red() << " " << c.green() << " " << c.blue() << "\t"; if (entry.name().isEmpty()) stream << "Untitled\n"; else stream << entry.name() << "\n"; } } return true; } bool KoColorSet::Private::loadGpl() { QString s = QString::fromUtf8(data.data(), data.count()); if (s.isEmpty() || s.isNull() || s.length() < 50) { warnPigment << "Illegal Gimp palette file: " << colorSet->filename(); return false; } quint32 index = 0; QStringList lines = s.split('\n', QString::SkipEmptyParts); if (lines.size() < 3) { warnPigment << "Not enough lines in palette file: " << colorSet->filename(); return false; } QString columnsText; qint32 r, g, b; KisSwatch e; // Read name if (!lines[0].startsWith("GIMP") || !lines[1].toLower().contains("name")) { warnPigment << "Illegal Gimp palette file: " << colorSet->filename(); return false; } colorSet->setName(i18n(lines[1].split(":")[1].trimmed().toLatin1())); index = 2; // Read columns int columns = 0; if (lines[index].toLower().contains("columns")) { columnsText = lines[index].split(":")[1].trimmed(); columns = columnsText.toInt(); global().setColumnCount(columns); index = 3; } for (qint32 i = index; i < lines.size(); i++) { if (lines[i].startsWith('#')) { comment += lines[i].mid(1).trimmed() + ' '; } else if (!lines[i].isEmpty()) { QStringList a = lines[i].replace('\t', ' ').split(' ', QString::SkipEmptyParts); if (a.count() < 3) { break; } r = qBound(0, a[0].toInt(), 255); g = qBound(0, a[1].toInt(), 255); b = qBound(0, a[2].toInt(), 255); e.setColor(KoColor(QColor(r, g, b), KoColorSpaceRegistry::instance()->rgb8())); for (int i = 0; i != 3; i++) { a.pop_front(); } QString name = a.join(" "); e.setName(name.isEmpty() ? i18n("Untitled") : name); global().addEntry(e); } } int rowCount = global().colorCount()/ global().columnCount(); if (global().colorCount() % global().columnCount()>0) { rowCount ++; } global().setRowCount(rowCount); return true; } bool KoColorSet::Private::loadAct() { QFileInfo info(colorSet->filename()); colorSet->setName(info.baseName()); KisSwatch e; for (int i = 0; i < data.size(); i += 3) { quint8 r = data[i]; quint8 g = data[i+1]; quint8 b = data[i+2]; e.setColor(KoColor(QColor(r, g, b), KoColorSpaceRegistry::instance()->rgb8())); global().addEntry(e); } return true; } bool KoColorSet::Private::loadRiff() { // http://worms2d.info/Palette_file QFileInfo info(colorSet->filename()); colorSet->setName(info.baseName()); KisSwatch e; RiffHeader header; memcpy(&header, data.constData(), sizeof(RiffHeader)); header.colorcount = qFromBigEndian(header.colorcount); for (int i = sizeof(RiffHeader); (i < (int)(sizeof(RiffHeader) + header.colorcount) && i < data.size()); i += 4) { quint8 r = data[i]; quint8 g = data[i+1]; quint8 b = data[i+2]; e.setColor(KoColor(QColor(r, g, b), KoColorSpaceRegistry::instance()->rgb8())); groups[KoColorSet::GLOBAL_GROUP_NAME].addEntry(e); } return true; } bool KoColorSet::Private::loadPsp() { QFileInfo info(colorSet->filename()); colorSet->setName(info.baseName()); KisSwatch e; qint32 r, g, b; QString s = QString::fromUtf8(data.data(), data.count()); QStringList l = s.split('\n', QString::SkipEmptyParts); if (l.size() < 4) return false; if (l[0] != "JASC-PAL") return false; if (l[1] != "0100") return false; int entries = l[2].toInt(); for (int i = 0; i < entries; ++i) { QStringList a = l[i + 3].replace('\t', ' ').split(' ', QString::SkipEmptyParts); if (a.count() != 3) { continue; } r = qBound(0, a[0].toInt(), 255); g = qBound(0, a[1].toInt(), 255); b = qBound(0, a[2].toInt(), 255); e.setColor(KoColor(QColor(r, g, b), KoColorSpaceRegistry::instance()->rgb8())); QString name = a.join(" "); e.setName(name.isEmpty() ? i18n("Untitled") : name); groups[KoColorSet::GLOBAL_GROUP_NAME].addEntry(e); } return true; } bool KoColorSet::Private::loadKpl() { QBuffer buf(&data); buf.open(QBuffer::ReadOnly); QScopedPointer store(KoStore::createStore(&buf, KoStore::Read, "krita/x-colorset", KoStore::Zip)); if (!store || store->bad()) { return false; } if (store->hasFile("profiles.xml")) { if (!store->open("profiles.xml")) { return false; } QByteArray data; data.resize(store->size()); QByteArray ba = store->read(store->size()); store->close(); QDomDocument doc; doc.setContent(ba); QDomElement e = doc.documentElement(); QDomElement c = e.firstChildElement(KPL_PALETTE_PROFILE_TAG); while (!c.isNull()) { QString name = c.attribute(KPL_PALETTE_NAME_ATTR); QString filename = c.attribute(KPL_PALETTE_FILENAME_ATTR); QString colorModelId = c.attribute(KPL_COLOR_MODEL_ID_ATTR); QString colorDepthId = c.attribute(KPL_COLOR_DEPTH_ID_ATTR); if (!KoColorSpaceRegistry::instance()->profileByName(name)) { store->open(filename); QByteArray data; data.resize(store->size()); data = store->read(store->size()); store->close(); const KoColorProfile *profile = KoColorSpaceRegistry::instance()->createColorProfile(colorModelId, colorDepthId, data); if (profile && profile->valid()) { KoColorSpaceRegistry::instance()->addProfile(profile); } } c = c.nextSiblingElement(); } } { if (!store->open("colorset.xml")) { return false; } QByteArray data; data.resize(store->size()); QByteArray ba = store->read(store->size()); store->close(); QDomDocument doc; doc.setContent(ba); QDomElement e = doc.documentElement(); colorSet->setName(e.attribute(KPL_PALETTE_NAME_ATTR)); colorSet->setColumnCount(e.attribute(KPL_PALETTE_COLUMN_COUNT_ATTR).toInt()); colorSet->setIsEditable(e.attribute(KPL_PALETTE_READONLY_ATTR) != "true"); comment = e.attribute(KPL_PALETTE_COMMENT_ATTR); loadKplGroup(doc, e, colorSet->getGlobalGroup()); QDomElement g = e.firstChildElement(KPL_GROUP_TAG); while (!g.isNull()) { QString groupName = g.attribute(KPL_GROUP_NAME_ATTR); colorSet->addGroup(groupName); loadKplGroup(doc, g, colorSet->getGroup(groupName)); g = g.nextSiblingElement(KPL_GROUP_TAG); } } buf.close(); return true; } bool KoColorSet::Private::loadAco() { QFileInfo info(colorSet->filename()); colorSet->setName(info.baseName()); QBuffer buf(&data); buf.open(QBuffer::ReadOnly); quint16 version = readShort(&buf); quint16 numColors = readShort(&buf); KisSwatch e; if (version == 1 && buf.size() > 4+numColors*10) { buf.seek(4+numColors*10); version = readShort(&buf); numColors = readShort(&buf); } const quint16 quint16_MAX = 65535; for (int i = 0; i < numColors && !buf.atEnd(); ++i) { quint16 colorSpace = readShort(&buf); quint16 ch1 = readShort(&buf); quint16 ch2 = readShort(&buf); quint16 ch3 = readShort(&buf); quint16 ch4 = readShort(&buf); bool skip = false; if (colorSpace == 0) { // RGB const KoColorProfile *srgb = KoColorSpaceRegistry::instance()->rgb8()->profile(); KoColor c(KoColorSpaceRegistry::instance()->rgb16(srgb)); reinterpret_cast(c.data())[0] = ch3; reinterpret_cast(c.data())[1] = ch2; reinterpret_cast(c.data())[2] = ch1; c.setOpacity(OPACITY_OPAQUE_U8); e.setColor(c); } else if (colorSpace == 1) { // HSB QColor qc; qc.setHsvF(ch1 / 65536.0, ch2 / 65536.0, ch3 / 65536.0); KoColor c(qc, KoColorSpaceRegistry::instance()->rgb16()); c.setOpacity(OPACITY_OPAQUE_U8); e.setColor(c); } else if (colorSpace == 2) { // CMYK KoColor c(KoColorSpaceRegistry::instance()->colorSpace(CMYKAColorModelID.id(), Integer16BitsColorDepthID.id(), QString())); reinterpret_cast(c.data())[0] = quint16_MAX - ch1; reinterpret_cast(c.data())[1] = quint16_MAX - ch2; reinterpret_cast(c.data())[2] = quint16_MAX - ch3; reinterpret_cast(c.data())[3] = quint16_MAX - ch4; c.setOpacity(OPACITY_OPAQUE_U8); e.setColor(c); } else if (colorSpace == 7) { // LAB KoColor c = KoColor(KoColorSpaceRegistry::instance()->lab16()); reinterpret_cast(c.data())[0] = ch3; reinterpret_cast(c.data())[1] = ch2; reinterpret_cast(c.data())[2] = ch1; c.setOpacity(OPACITY_OPAQUE_U8); e.setColor(c); } else if (colorSpace == 8) { // GRAY KoColor c(KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer16BitsColorDepthID.id(), QString())); reinterpret_cast(c.data())[0] = ch1 * (quint16_MAX / 10000); c.setOpacity(OPACITY_OPAQUE_U8); e.setColor(c); } else { warnPigment << "Unsupported colorspace in palette" << colorSet->filename() << "(" << colorSpace << ")"; skip = true; } if (version == 2) { quint16 v2 = readShort(&buf); //this isn't a version, it's a marker and needs to be skipped. Q_UNUSED(v2); quint16 size = readShort(&buf) -1; //then comes the length if (size>0) { QByteArray ba = buf.read(size*2); if (ba.size() == size*2) { QTextCodec *Utf16Codec = QTextCodec::codecForName("UTF-16BE"); e.setName(Utf16Codec->toUnicode(ba)); } else { warnPigment << "Version 2 name block is the wrong size" << colorSet->filename(); } } v2 = readShort(&buf); //end marker also needs to be skipped. Q_UNUSED(v2); } if (!skip) { groups[KoColorSet::GLOBAL_GROUP_NAME].addEntry(e); } } return true; } bool KoColorSet::Private::loadSbz() { QBuffer buf(&data); buf.open(QBuffer::ReadOnly); // &buf is a subclass of QIODevice QScopedPointer store(KoStore::createStore(&buf, KoStore::Read, "application/x-swatchbook", KoStore::Zip)); if (!store || store->bad()) return false; if (store->hasFile("swatchbook.xml")) { // Try opening... if (!store->open("swatchbook.xml")) { return false; } QByteArray data; data.resize(store->size()); QByteArray ba = store->read(store->size()); store->close(); dbgPigment << "XML palette: " << colorSet->filename() << ", SwatchBooker format"; QDomDocument doc; int errorLine, errorColumn; QString errorMessage; bool status = doc.setContent(ba, &errorMessage, &errorLine, &errorColumn); if (!status) { warnPigment << "Illegal XML palette:" << colorSet->filename(); warnPigment << "Error (line" << errorLine << ", column" << errorColumn << "):" << errorMessage; return false; } QDomElement e = doc.documentElement(); // SwatchBook // Start reading properties... QDomElement metadata = e.firstChildElement("metadata"); if (e.isNull()) { warnPigment << "Palette metadata not found"; return false; } QDomElement title = metadata.firstChildElement("dc:title"); QString colorName = title.text(); colorName = colorName.isEmpty() ? i18n("Untitled") : colorName; colorSet->setName(colorName); dbgPigment << "Processed name of palette:" << colorSet->name(); // End reading properties // Now read colors... QDomElement materials = e.firstChildElement("materials"); if (materials.isNull()) { warnPigment << "Materials (color definitions) not found"; return false; } // This one has lots of "color" elements QDomElement colorElement = materials.firstChildElement("color"); if (colorElement.isNull()) { warnPigment << "Color definitions not found (line" << materials.lineNumber() << ", column" << materials.columnNumber() << ")"; return false; } // Also read the swatch book... QDomElement book = e.firstChildElement("book"); if (book.isNull()) { warnPigment << "Palette book (swatch composition) not found (line" << e.lineNumber() << ", column" << e.columnNumber() << ")"; return false; } // Which has lots of "swatch"es (todo: support groups) QDomElement swatch = book.firstChildElement(); if (swatch.isNull()) { warnPigment << "Swatches/groups definition not found (line" << book.lineNumber() << ", column" << book.columnNumber() << ")"; return false; } // We'll store colors here, and as we process swatches // we'll add them to the palette QHash materialsBook; QHash fileColorSpaces; // Color processing for(; !colorElement.isNull(); colorElement = colorElement.nextSiblingElement("color")) { KisSwatch currentEntry; // Set if color is spot currentEntry.setSpotColor(colorElement.attribute("usage") == "spot"); // inside contains id and name // one or more define the color QDomElement currentColorMetadata = colorElement.firstChildElement("metadata"); QDomNodeList currentColorValues = colorElement.elementsByTagName("values"); // Get color name QDomElement colorTitle = currentColorMetadata.firstChildElement("dc:title"); QDomElement colorId = currentColorMetadata.firstChildElement("dc:identifier"); // Is there an id? (we need that at the very least for identifying a color) if (colorId.text().isEmpty()) { warnPigment << "Unidentified color (line" << colorId.lineNumber()<< ", column" << colorId.columnNumber() << ")"; return false; } if (materialsBook.contains(colorId.text())) { warnPigment << "Duplicated color definition (line" << colorId.lineNumber()<< ", column" << colorId.columnNumber() << ")"; return false; } // Get a valid color name currentEntry.setId(colorId.text()); currentEntry.setName(colorTitle.text().isEmpty() ? colorId.text() : colorTitle.text()); // Get a valid color definition if (currentColorValues.isEmpty()) { warnPigment << "Color definitions not found (line" << colorElement.lineNumber() << ", column" << colorElement.columnNumber() << ")"; return false; } bool firstDefinition = false; const KoColorProfile *srgb = KoColorSpaceRegistry::instance()->rgb8()->profile(); // Priority: Lab, otherwise the first definition found for(int j = 0; j < currentColorValues.size(); j++) { QDomNode colorValue = currentColorValues.at(j); QDomElement colorValueE = colorValue.toElement(); QString model = colorValueE.attribute("model", QString()); // sRGB,RGB,HSV,HSL,CMY,CMYK,nCLR: 0 -> 1 // YIQ: Y 0 -> 1 : IQ -0.5 -> 0.5 // Lab: L 0 -> 100 : ab -128 -> 127 // XYZ: 0 -> ~100 if (model == "Lab") { QStringList lab = colorValueE.text().split(" "); if (lab.length() != 3) { warnPigment << "Invalid Lab color definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; } float l = lab.at(0).toFloat(&status); float a = lab.at(1).toFloat(&status); float b = lab.at(2).toFloat(&status); if (!status) { warnPigment << "Invalid float definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; } KoColor c(KoColorSpaceRegistry::instance()->colorSpace(LABAColorModelID.id(), Float32BitsColorDepthID.id(), QString())); reinterpret_cast(c.data())[0] = l; reinterpret_cast(c.data())[1] = a; reinterpret_cast(c.data())[2] = b; c.setOpacity(OPACITY_OPAQUE_F); firstDefinition = true; currentEntry.setColor(c); break; // Immediately add this one } else if (model == "sRGB" && !firstDefinition) { QStringList rgb = colorValueE.text().split(" "); if (rgb.length() != 3) { warnPigment << "Invalid sRGB color definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; } float r = rgb.at(0).toFloat(&status); float g = rgb.at(1).toFloat(&status); float b = rgb.at(2).toFloat(&status); if (!status) { warnPigment << "Invalid float definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; } KoColor c(KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(), Float32BitsColorDepthID.id(), srgb)); reinterpret_cast(c.data())[0] = r; reinterpret_cast(c.data())[1] = g; reinterpret_cast(c.data())[2] = b; c.setOpacity(OPACITY_OPAQUE_F); currentEntry.setColor(c); firstDefinition = true; } else if (model == "XYZ" && !firstDefinition) { QStringList xyz = colorValueE.text().split(" "); if (xyz.length() != 3) { warnPigment << "Invalid XYZ color definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; } float x = xyz.at(0).toFloat(&status); float y = xyz.at(1).toFloat(&status); float z = xyz.at(2).toFloat(&status); if (!status) { warnPigment << "Invalid float definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; } KoColor c(KoColorSpaceRegistry::instance()->colorSpace(XYZAColorModelID.id(), Float32BitsColorDepthID.id(), QString())); reinterpret_cast(c.data())[0] = x; reinterpret_cast(c.data())[1] = y; reinterpret_cast(c.data())[2] = z; c.setOpacity(OPACITY_OPAQUE_F); currentEntry.setColor(c); firstDefinition = true; } // The following color spaces admit an ICC profile (in SwatchBooker) else if (model == "CMYK" && !firstDefinition) { QStringList cmyk = colorValueE.text().split(" "); if (cmyk.length() != 4) { warnPigment << "Invalid CMYK color definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; } float c = cmyk.at(0).toFloat(&status); float m = cmyk.at(1).toFloat(&status); float y = cmyk.at(2).toFloat(&status); float k = cmyk.at(3).toFloat(&status); if (!status) { warnPigment << "Invalid float definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; } QString space = colorValueE.attribute("space"); const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->colorSpace(CMYKAColorModelID.id(), Float32BitsColorDepthID.id(), QString()); if (!space.isEmpty()) { // Try loading the profile and add it to the registry if (!fileColorSpaces.contains(space)) { store->enterDirectory("profiles"); store->open(space); QByteArray data; data.resize(store->size()); data = store->read(store->size()); store->close(); const KoColorProfile *profile = KoColorSpaceRegistry::instance()->createColorProfile(CMYKAColorModelID.id(), Float32BitsColorDepthID.id(), data); if (profile && profile->valid()) { KoColorSpaceRegistry::instance()->addProfile(profile); colorSpace = KoColorSpaceRegistry::instance()->colorSpace(CMYKAColorModelID.id(), Float32BitsColorDepthID.id(), profile); fileColorSpaces.insert(space, colorSpace); } } else { colorSpace = fileColorSpaces.value(space); } } KoColor color(colorSpace); reinterpret_cast(color.data())[0] = c; reinterpret_cast(color.data())[1] = m; reinterpret_cast(color.data())[2] = y; reinterpret_cast(color.data())[3] = k; color.setOpacity(OPACITY_OPAQUE_F); currentEntry.setColor(color); firstDefinition = true; } else if (model == "GRAY" && !firstDefinition) { QString gray = colorValueE.text(); float g = gray.toFloat(&status); if (!status) { warnPigment << "Invalid float definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; } QString space = colorValueE.attribute("space"); const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Float32BitsColorDepthID.id(), QString()); if (!space.isEmpty()) { // Try loading the profile and add it to the registry if (!fileColorSpaces.contains(space)) { store->enterDirectory("profiles"); store->open(space); QByteArray data; data.resize(store->size()); data = store->read(store->size()); store->close(); const KoColorProfile *profile = KoColorSpaceRegistry::instance()->createColorProfile(CMYKAColorModelID.id(), Float32BitsColorDepthID.id(), data); if (profile && profile->valid()) { KoColorSpaceRegistry::instance()->addProfile(profile); colorSpace = KoColorSpaceRegistry::instance()->colorSpace(CMYKAColorModelID.id(), Float32BitsColorDepthID.id(), profile); fileColorSpaces.insert(space, colorSpace); } } else { colorSpace = fileColorSpaces.value(space); } } KoColor c(colorSpace); reinterpret_cast(c.data())[0] = g; c.setOpacity(OPACITY_OPAQUE_F); currentEntry.setColor(c); firstDefinition = true; } else if (model == "RGB" && !firstDefinition) { QStringList rgb = colorValueE.text().split(" "); if (rgb.length() != 3) { warnPigment << "Invalid RGB color definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; } float r = rgb.at(0).toFloat(&status); float g = rgb.at(1).toFloat(&status); float b = rgb.at(2).toFloat(&status); if (!status) { warnPigment << "Invalid float definition (line" << colorValueE.lineNumber() << ", column" << colorValueE.columnNumber() << ")"; } QString space = colorValueE.attribute("space"); const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(), Float32BitsColorDepthID.id(), srgb); if (!space.isEmpty()) { // Try loading the profile and add it to the registry if (!fileColorSpaces.contains(space)) { store->enterDirectory("profiles"); store->open(space); QByteArray data; data.resize(store->size()); data = store->read(store->size()); store->close(); const KoColorProfile *profile = KoColorSpaceRegistry::instance()->createColorProfile(RGBAColorModelID.id(), Float32BitsColorDepthID.id(), data); if (profile && profile->valid()) { KoColorSpaceRegistry::instance()->addProfile(profile); colorSpace = KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(), Float32BitsColorDepthID.id(), profile); fileColorSpaces.insert(space, colorSpace); } } else { colorSpace = fileColorSpaces.value(space); } } KoColor c(colorSpace); reinterpret_cast(c.data())[0] = r; reinterpret_cast(c.data())[1] = g; reinterpret_cast(c.data())[2] = b; c.setOpacity(OPACITY_OPAQUE_F); currentEntry.setColor(c); firstDefinition = true; } else { warnPigment << "Color space not implemented:" << model << "(line" << colorValueE.lineNumber() << ", column "<< colorValueE.columnNumber() << ")"; } } if (firstDefinition) { materialsBook.insert(currentEntry.id(), currentEntry); } else { warnPigment << "No supported color spaces for the current color (line" << colorElement.lineNumber() << ", column "<< colorElement.columnNumber() << ")"; return false; } } // End colors // Now decide which ones will go into the palette for(;!swatch.isNull(); swatch = swatch.nextSiblingElement()) { QString type = swatch.tagName(); if (type.isEmpty() || type.isNull()) { warnPigment << "Invalid swatch/group definition (no id) (line" << swatch.lineNumber() << ", column" << swatch.columnNumber() << ")"; return false; } else if (type == "swatch") { QString id = swatch.attribute("material"); if (id.isEmpty() || id.isNull()) { warnPigment << "Invalid swatch definition (no material id) (line" << swatch.lineNumber() << ", column" << swatch.columnNumber() << ")"; return false; } if (materialsBook.contains(id)) { groups[KoColorSet::GLOBAL_GROUP_NAME].addEntry(materialsBook.value(id)); } else { warnPigment << "Invalid swatch definition (material not found) (line" << swatch.lineNumber() << ", column" << swatch.columnNumber() << ")"; return false; } } else if (type == "group") { QDomElement groupMetadata = swatch.firstChildElement("metadata"); if (groupMetadata.isNull()) { warnPigment << "Invalid group definition (missing metadata) (line" << groupMetadata.lineNumber() << ", column" << groupMetadata.columnNumber() << ")"; return false; } QDomElement groupTitle = metadata.firstChildElement("dc:title"); if (groupTitle.isNull()) { warnPigment << "Invalid group definition (missing title) (line" << groupTitle.lineNumber() << ", column" << groupTitle.columnNumber() << ")"; return false; } QString currentGroupName = groupTitle.text(); QDomElement groupSwatch = swatch.firstChildElement("swatch"); while(!groupSwatch.isNull()) { QString id = groupSwatch.attribute("material"); if (id.isEmpty() || id.isNull()) { warnPigment << "Invalid swatch definition (no material id) (line" << groupSwatch.lineNumber() << ", column" << groupSwatch.columnNumber() << ")"; return false; } if (materialsBook.contains(id)) { groups[currentGroupName].addEntry(materialsBook.value(id)); } else { warnPigment << "Invalid swatch definition (material not found) (line" << groupSwatch.lineNumber() << ", column" << groupSwatch.columnNumber() << ")"; return false; } groupSwatch = groupSwatch.nextSiblingElement("swatch"); } } } // End palette } buf.close(); return true; } bool KoColorSet::Private::loadXml() { bool res = false; QXmlStreamReader *xml = new QXmlStreamReader(data); if (xml->readNextStartElement()) { QStringRef paletteId = xml->name(); if (QStringRef::compare(paletteId, "SCRIBUSCOLORS", Qt::CaseInsensitive) == 0) { // Scribus dbgPigment << "XML palette: " << colorSet->filename() << ", Scribus format"; res = loadScribusXmlPalette(colorSet, xml); } else { // Unknown XML format xml->raiseError("Unknown XML palette format. Expected SCRIBUSCOLORS, found " + paletteId); } } // If there is any error (it should be returned through the stream) if (xml->hasError() || !res) { warnPigment << "Illegal XML palette:" << colorSet->filename(); warnPigment << "Error (line"<< xml->lineNumber() << ", column" << xml->columnNumber() << "):" << xml->errorString(); return false; } else { dbgPigment << "XML palette parsed successfully:" << colorSet->filename(); return true; } } bool KoColorSet::Private::saveKpl(QIODevice *dev) const { QScopedPointer store(KoStore::createStore(dev, KoStore::Write, "krita/x-colorset", KoStore::Zip)); if (!store || store->bad()) return false; QSet colorSpaces; { QDomDocument doc; QDomElement root = doc.createElement(KPL_PALETTE_TAG); root.setAttribute(KPL_VERSION_ATTR, "1.0"); root.setAttribute(KPL_PALETTE_NAME_ATTR, colorSet->name()); root.setAttribute(KPL_PALETTE_COMMENT_ATTR, comment); root.setAttribute(KPL_PALETTE_READONLY_ATTR, (colorSet->isEditable() || !colorSet->isGlobal()) ? "false" : "true"); root.setAttribute(KPL_PALETTE_COLUMN_COUNT_ATTR, colorSet->columnCount()); root.setAttribute(KPL_GROUP_ROW_COUNT_ATTR, groups[KoColorSet::GLOBAL_GROUP_NAME].rowCount()); saveKplGroup(doc, root, colorSet->getGroup(KoColorSet::GLOBAL_GROUP_NAME), colorSpaces); for (const QString &groupName : groupNames) { if (groupName == KoColorSet::GLOBAL_GROUP_NAME) { continue; } QDomElement gl = doc.createElement(KPL_GROUP_TAG); gl.setAttribute(KPL_GROUP_NAME_ATTR, groupName); root.appendChild(gl); saveKplGroup(doc, gl, colorSet->getGroup(groupName), colorSpaces); } doc.appendChild(root); if (!store->open("colorset.xml")) { return false; } QByteArray ba = doc.toByteArray(); if (store->write(ba) != ba.size()) { return false; } if (!store->close()) { return false; } } QDomDocument doc; QDomElement profileElement = doc.createElement("Profiles"); for (const KoColorSpace *colorSpace : colorSpaces) { QString fn = QFileInfo(colorSpace->profile()->fileName()).fileName(); if (!store->open(fn)) { return false; } QByteArray profileRawData = colorSpace->profile()->rawData(); if (!store->write(profileRawData)) { return false; } if (!store->close()) { return false; } QDomElement el = doc.createElement(KPL_PALETTE_PROFILE_TAG); el.setAttribute(KPL_PALETTE_FILENAME_ATTR, fn); el.setAttribute(KPL_PALETTE_NAME_ATTR, colorSpace->profile()->name()); el.setAttribute(KPL_COLOR_MODEL_ID_ATTR, colorSpace->colorModelId().id()); el.setAttribute(KPL_COLOR_DEPTH_ID_ATTR, colorSpace->colorDepthId().id()); profileElement.appendChild(el); } doc.appendChild(profileElement); if (!store->open("profiles.xml")) { return false; } QByteArray ba = doc.toByteArray(); if (store->write(ba) != ba.size()) { return false; } if (!store->close()) { return false; } return store->finalize(); } void KoColorSet::Private::saveKplGroup(QDomDocument &doc, QDomElement &groupEle, const KisSwatchGroup *group, QSet &colorSetSet) const { groupEle.setAttribute(KPL_GROUP_ROW_COUNT_ATTR, QString::number(group->rowCount())); for (const SwatchInfoType &info : group->infoList()) { const KoColorProfile *profile = info.swatch.color().colorSpace()->profile(); // Only save non-builtin profiles.= if (!profile->fileName().isEmpty()) { colorSetSet.insert(info.swatch.color().colorSpace()); } QDomElement swatchEle = doc.createElement(KPL_SWATCH_TAG); swatchEle.setAttribute(KPL_SWATCH_NAME_ATTR, info.swatch.name()); swatchEle.setAttribute(KPL_SWATCH_ID_ATTR, info.swatch.id()); swatchEle.setAttribute(KPL_SWATCH_SPOT_ATTR, info.swatch.spotColor() ? "true" : "false"); swatchEle.setAttribute(KPL_SWATCH_BITDEPTH_ATTR, info.swatch.color().colorSpace()->colorDepthId().id()); info.swatch.color().toXML(doc, swatchEle); QDomElement positionEle = doc.createElement(KPL_SWATCH_POS_TAG); positionEle.setAttribute(KPL_SWATCH_ROW_ATTR, info.row); positionEle.setAttribute(KPL_SWATCH_COL_ATTR, info.column); swatchEle.appendChild(positionEle); groupEle.appendChild(swatchEle); } } void KoColorSet::Private::loadKplGroup(const QDomDocument &doc, const QDomElement &parentEle, KisSwatchGroup *group) { Q_UNUSED(doc); if (!parentEle.attribute(KPL_GROUP_ROW_COUNT_ATTR).isNull()) { group->setRowCount(parentEle.attribute(KPL_GROUP_ROW_COUNT_ATTR).toInt()); } group->setColumnCount(colorSet->columnCount()); for (QDomElement swatchEle = parentEle.firstChildElement(KPL_SWATCH_TAG); !swatchEle.isNull(); swatchEle = swatchEle.nextSiblingElement(KPL_SWATCH_TAG)) { QString colorDepthId = swatchEle.attribute(KPL_SWATCH_BITDEPTH_ATTR, Integer8BitsColorDepthID.id()); KisSwatch entry; entry.setColor(KoColor::fromXML(swatchEle.firstChildElement(), colorDepthId)); entry.setName(swatchEle.attribute(KPL_SWATCH_NAME_ATTR)); entry.setId(swatchEle.attribute(KPL_SWATCH_ID_ATTR)); entry.setSpotColor(swatchEle.attribute(KPL_SWATCH_SPOT_ATTR, "false") == "true" ? true : false); QDomElement positionEle = swatchEle.firstChildElement(KPL_SWATCH_POS_TAG); if (!positionEle.isNull()) { int rowNumber = positionEle.attribute(KPL_SWATCH_ROW_ATTR).toInt(); int columnNumber = positionEle.attribute(KPL_SWATCH_COL_ATTR).toInt(); if (columnNumber < 0 || columnNumber >= colorSet->columnCount() || rowNumber < 0 ) { warnPigment << "Swatch" << entry.name() << "of palette" << colorSet->name() << "has invalid position."; continue; } group->setEntry(entry, columnNumber, rowNumber); } else { group->addEntry(entry); } } if (parentEle.attribute(KPL_GROUP_ROW_COUNT_ATTR).isNull() && group->colorCount()/group->columnCount()+1 < 20) { group->setRowCount(group->colorCount()/group->columnCount()+1); } } diff --git a/libs/pigment/resources/KoColorSet.h b/libs/pigment/resources/KoColorSet.h index 8ddbc6fb67..aa8a2bff8f 100644 --- a/libs/pigment/resources/KoColorSet.h +++ b/libs/pigment/resources/KoColorSet.h @@ -1,216 +1,219 @@ /* This file is part of the KDE project Copyright (c) 2005 Boudewijn Rempt Copyright (c) 2016 L. E. Segovia 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 KOCOLORSET #define KOCOLORSET #include #include #include #include +#include #include #include "KoColor.h" #include "KisSwatch.h" #include "KisSwatchGroup.h" /** * Also called palette. * Open Gimp, Photoshop or RIFF palette files. This is a straight port * from the Gimp. */ -class KRITAPIGMENT_EXPORT KoColorSet : public QObject, public KoResource +class KRITAPIGMENT_EXPORT KoColorSet :public KoResource { - Q_OBJECT public: static const QString GLOBAL_GROUP_NAME; static const QString KPL_VERSION_ATTR; static const QString KPL_GROUP_ROW_COUNT_ATTR; static const QString KPL_PALETTE_COLUMN_COUNT_ATTR; static const QString KPL_PALETTE_NAME_ATTR; static const QString KPL_PALETTE_COMMENT_ATTR; static const QString KPL_PALETTE_FILENAME_ATTR; static const QString KPL_PALETTE_READONLY_ATTR; static const QString KPL_COLOR_MODEL_ID_ATTR; static const QString KPL_COLOR_DEPTH_ID_ATTR; static const QString KPL_GROUP_NAME_ATTR; static const QString KPL_SWATCH_ROW_ATTR; static const QString KPL_SWATCH_COL_ATTR; static const QString KPL_SWATCH_NAME_ATTR; static const QString KPL_SWATCH_SPOT_ATTR; static const QString KPL_SWATCH_ID_ATTR; static const QString KPL_SWATCH_BITDEPTH_ATTR; static const QString KPL_PALETTE_PROFILE_TAG; static const QString KPL_SWATCH_POS_TAG; static const QString KPL_SWATCH_TAG; static const QString KPL_GROUP_TAG; static const QString KPL_PALETTE_TAG; public: enum PaletteType { UNKNOWN = 0, GPL, // GIMP RIFF_PAL, // RIFF ACT, // Photoshop binary PSP_PAL, // PaintShop Pro ACO, // Photoshop Swatches XML, // XML palette (Scribus) KPL, // KoColor-based XML palette SBZ // SwatchBooker }; /** * Load a color set from a file. This can be a Gimp * palette, a RIFF palette, a Photoshop palette, * a Krita palette, * a Scribus palette or a SwatchBooker palette. */ explicit KoColorSet(const QString &filename = QString()); // Explicit copy constructor (KoResource copy constructor is private) KoColorSet(const KoColorSet& rhs); public /* overridden methods */: // KoResource ~KoColorSet() override; bool load() override; bool loadFromDevice(QIODevice *dev) override; bool save() override; bool saveToDevice(QIODevice* dev) const override; QString defaultFileExtension() const override; public /* methods */: void setColumnCount(int columns); int columnCount() const; void setComment(QString comment); QString comment(); int rowCount() const; quint32 colorCount() const; PaletteType paletteType() const; void setPaletteType(PaletteType paletteType); /** * @brief isGlobal * A global color set is a set stored in the config directory * Such a color set would be opened every time Krita is launched. * * A non-global color set, on contrary, would be stored in a kra file, * and would only be opened when that file is opened by Krita. * @return */ bool isGlobal() const; void setIsGlobal(bool); bool isEditable() const; void setIsEditable(bool isEditable); QByteArray toByteArray() const; bool fromByteArray(QByteArray &data); /** * @brief add Add a color to the palette. * @param groupName color to add the group to. If empty, it will be added to the unsorted. */ void add(const KisSwatch &, const QString &groupName = GLOBAL_GROUP_NAME); void setEntry(const KisSwatch &e, int x, int y, const QString &groupName = GLOBAL_GROUP_NAME); /** * @brief getColorGlobal * A function for getting a color based on a global index. Useful for itterating through all color entries. * @param globalIndex the global index over the whole palette. * @return the entry. */ KisSwatch getColorGlobal(quint32 x, quint32 y) const; /** * @brief getColorGroup * A function for getting the color from a specific group. * @param groupName the name of the group, will give unosrted when not defined. * @param index the index within the group. * @return the entry */ KisSwatch getColorGroup(quint32 x, quint32 y, QString groupName); /** * @brief getGroupNames * @return returns a list of group names, excluding the unsorted group. */ QStringList getGroupNames(); /** * @brief getGroup * @param name * @return the group with the name given; global group if no parameter is given * null pointer if not found. */ KisSwatchGroup *getGroup(const QString &name); KisSwatchGroup *getGlobalGroup(); bool changeGroupName(const QString &oldGroupName, const QString &newGroupName); /** * @brief addGroup * Adds a new group. * @param groupName the name of the new group. When not specified, this will fail. * @return whether thegroup was made. */ bool addGroup(const QString &groupName); /** * @brief moveGroup * Move a group in the internal stringlist. * @param groupName the groupname to move. * @param groupNameInsertBefore the groupname to insert before. Empty means it will be added to the end. * @return */ bool moveGroup(const QString &groupName, const QString &groupNameInsertBefore = GLOBAL_GROUP_NAME); /** * @brief removeGroup * Remove a group from the KoColorSet * @param groupName the name of the group you want to remove. * @param keepColors Whether you wish to keep the colorsetentries. These will be added to the unsorted. * @return whether it could find the group to remove. */ bool removeGroup(const QString &groupName, bool keepColors = true); void clear(); /** * @brief getIndexClosestColor * function that matches the color to all colors in the colorset, and returns the index * of the closest match. * @param color the color you wish to compare. * @param useGivenColorSpace whether to use the color space of the color given * when the two colors' colorspaces don't match. Else it'll use the entry's colorspace. * @return returns the int of the closest match. */ KisSwatchGroup::SwatchInfo getClosestColorInfo(KoColor compare, bool useGivenColorSpace = true); private: class Private; const QScopedPointer d; }; + +typedef QSharedPointer KoColorSetSP; + #endif // KOCOLORSET diff --git a/libs/pigment/resources/KoColorSet_p.h b/libs/pigment/resources/KoColorSet_p.h index 3659d88aef..ca4551c871 100644 --- a/libs/pigment/resources/KoColorSet_p.h +++ b/libs/pigment/resources/KoColorSet_p.h @@ -1,74 +1,74 @@ #ifndef KOCOLORSET_P_H #define KOCOLORSET_P_H #include #include #include #include #include #include #include "KoColorSet.h" struct RiffHeader { quint32 riff; quint32 size; quint32 signature; quint32 data; quint32 datasize; quint16 version; quint16 colorcount; }; class KoColorSet::Private { private: typedef KisSwatchGroup::SwatchInfo SwatchInfoType; public: - Private(KoColorSet *a_colorSet); + Private(KoColorSetSP a_colorSet); public: KisSwatchGroup &global() { Q_ASSERT(groups.contains(GLOBAL_GROUP_NAME)); return groups[GLOBAL_GROUP_NAME]; } public: bool init(); bool saveGpl(QIODevice *dev) const; bool loadGpl(); bool loadAct(); bool loadRiff(); bool loadPsp(); bool loadAco(); bool loadXml(); bool loadSbz(); bool saveKpl(QIODevice *dev) const; bool loadKpl(); public: - KoColorSet *colorSet; + KoColorSetSP colorSet; KoColorSet::PaletteType paletteType; QByteArray data; QString comment; QStringList groupNames; //names of the groups, this is used to determine the order they are in. QHash groups; //grouped colors. bool isGlobal; bool isEditable; private: KoColorSet::PaletteType detectFormat(const QString &fileName, const QByteArray &ba); - void scribusParseColor(KoColorSet *set, QXmlStreamReader *xml); - bool loadScribusXmlPalette(KoColorSet *set, QXmlStreamReader *xml); + void scribusParseColor(KoColorSetSP set, QXmlStreamReader *xml); + bool loadScribusXmlPalette(KoColorSetSP set, QXmlStreamReader *xml); quint16 readShort(QIODevice *io); void saveKplGroup(QDomDocument &doc, QDomElement &groupEle, const KisSwatchGroup *group, QSet &colorSetSet) const; void loadKplGroup(const QDomDocument &doc, const QDomElement &parentElement, KisSwatchGroup *group); }; #endif // KOCOLORSET_P_H diff --git a/libs/pigment/resources/KoPattern.cpp b/libs/pigment/resources/KoPattern.cpp index e87cd51591..383c07edbd 100644 --- a/libs/pigment/resources/KoPattern.cpp +++ b/libs/pigment/resources/KoPattern.cpp @@ -1,399 +1,399 @@ /* This file is part of the KDE project Copyright (c) 2000 Matthias Elter Copyright (c) 2004 Boudewijn Rempt 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 #include #include #include #include namespace { struct GimpPatternHeader { quint32 header_size; /* header_size = sizeof (PatternHeader) + brush name */ quint32 version; /* pattern file version # */ quint32 width; /* width of pattern */ quint32 height; /* height of pattern */ quint32 bytes; /* depth of pattern in bytes : 1, 2, 3 or 4*/ quint32 magic_number; /* GIMP brush magic number */ }; // Yes! This is _NOT_ what my pat.txt file says. It's really not 'GIMP', but 'GPAT' quint32 const GimpPatternMagic = (('G' << 24) + ('P' << 16) + ('A' << 8) + ('T' << 0)); } KoPattern::KoPattern(const QString& file) : KoResource(file) { } KoPattern::KoPattern(const QImage &image, const QString &name, const QString &folderName) : KoResource(QString()) { setPatternImage(image); setName(name); QFileInfo fileInfo(folderName + QDir::separator() + name + defaultFileExtension()); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(folderName + QDir::separator() + name + QString::number(i) + defaultFileExtension()); i++; } setFilename(fileInfo.filePath()); } KoPattern::~KoPattern() { } bool KoPattern::load() { QFile file(filename()); if (file.size() == 0) return false; bool result; if (!file.open(QIODevice::ReadOnly)) { qWarning() << "Can't open file " << filename(); return false; } result = loadFromDevice(&file); file.close(); return result; } bool KoPattern::loadPatFromDevice(QIODevice *dev) { QByteArray data = dev->readAll(); return init(data); } bool KoPattern::savePatToDevice(QIODevice* dev) const { // Header: header_size (24+name length),version,width,height,colordepth of brush,magic,name // depth: 1 = greyscale, 2 = greyscale + A, 3 = RGB, 4 = RGBA // magic = "GPAT", as a single uint32, the docs are wrong here! // name is UTF-8 (\0-terminated! The docs say nothing about this!) // _All_ data in network order, it seems! (not mentioned in gimp-2.2.8/devel-docs/pat.txt!!) // We only save RGBA at the moment // Version is 1 for now... GimpPatternHeader ph; QByteArray utf8Name = name().toUtf8(); char const* name = utf8Name.data(); int nameLength = qstrlen(name); ph.header_size = qToBigEndian((quint32)sizeof(GimpPatternHeader) + nameLength + 1); // trailing 0 ph.version = qToBigEndian((quint32)1); ph.width = qToBigEndian((quint32)width()); ph.height = qToBigEndian((quint32)height()); ph.bytes = qToBigEndian((quint32)4); ph.magic_number = qToBigEndian((quint32)GimpPatternMagic); QByteArray bytes = QByteArray::fromRawData(reinterpret_cast(&ph), sizeof(GimpPatternHeader)); int wrote = dev->write(bytes); bytes.clear(); if (wrote == -1) return false; wrote = dev->write(name, nameLength + 1); // Trailing 0 apparently! if (wrote == -1) return false; int k = 0; bytes.resize(width() * height() * 4); for (qint32 y = 0; y < height(); ++y) { for (qint32 x = 0; x < width(); ++x) { // RGBA only QRgb pixel = m_pattern.pixel(x, y); bytes[k++] = static_cast(qRed(pixel)); bytes[k++] = static_cast(qGreen(pixel)); bytes[k++] = static_cast(qBlue(pixel)); bytes[k++] = static_cast(qAlpha(pixel)); } } wrote = dev->write(bytes); if (wrote == -1) return false; KoResource::saveToDevice(dev); return true; } bool KoPattern::loadFromDevice(QIODevice *dev) { QString fileExtension; int index = filename().lastIndexOf('.'); if (index != -1) fileExtension = filename().mid(index + 1).toLower(); bool result; if (fileExtension == "pat") { result = loadPatFromDevice(dev); } else { QImage image; // Workaround for some OS (Debian, Ubuntu), where loading directly from the QIODevice // fails with "libpng error: IDAT: CRC error" QByteArray data = dev->readAll(); QBuffer buffer(&data); result = image.load(&buffer, fileExtension.toUpper().toLatin1()); setPatternImage(image); } return result; } bool KoPattern::save() { QFile file(filename()); file.open(QIODevice::WriteOnly | QIODevice::Truncate); bool res = saveToDevice(&file); file.close(); return res; } bool KoPattern::saveToDevice(QIODevice *dev) const { QString fileExtension; int index = filename().lastIndexOf('.'); if (index != -1) fileExtension = filename().mid(index + 1).toLower(); if (fileExtension == "pat") { return savePatToDevice(dev); } else { return m_pattern.save(dev, fileExtension.toUpper().toLatin1()); } return true; } bool KoPattern::init(QByteArray& bytes) { int dataSize = bytes.size(); const char* data = bytes.constData(); // load Gimp patterns GimpPatternHeader bh; qint32 k; char* name; if ((int)sizeof(GimpPatternHeader) > dataSize) { return false; } memcpy(&bh, data, sizeof(GimpPatternHeader)); bh.header_size = qFromBigEndian(bh.header_size); bh.version = qFromBigEndian(bh.version); bh.width = qFromBigEndian(bh.width); bh.height = qFromBigEndian(bh.height); bh.bytes = qFromBigEndian(bh.bytes); bh.magic_number = qFromBigEndian(bh.magic_number); if ((int)bh.header_size > dataSize || bh.header_size == 0) { return false; } int size = bh.header_size - sizeof(GimpPatternHeader); name = new char[size]; memcpy(name, data + sizeof(GimpPatternHeader), size); if (name[size - 1]) { delete[] name; return false; } // size -1 so we don't add the end 0 to the QString... setName(QString::fromLatin1(name, size -1)); delete[] name; if (bh.width == 0 || bh.height == 0) { return false; } QImage::Format imageFormat; if (bh.bytes == 1 || bh.bytes == 3) { imageFormat = QImage::Format_RGB32; } else { imageFormat = QImage::Format_ARGB32; } QImage pattern = QImage(bh.width, bh.height, imageFormat); if (pattern.isNull()) { return false; } k = bh.header_size; if (bh.bytes == 1) { // Grayscale qint32 val; for (quint32 y = 0; y < bh.height; ++y) { QRgb* pixels = reinterpret_cast( pattern.scanLine(y) ); for (quint32 x = 0; x < bh.width; ++x, ++k) { if (k > dataSize) { qWarning() << "failed to load grayscale pattern" << filename(); return false; } val = data[k]; pixels[x] = qRgb(val, val, val); } } // It was grayscale, so make the pattern as small as possible // by converting it to Indexed8 pattern = pattern.convertToFormat(QImage::Format_Indexed8); } else if (bh.bytes == 2) { // Grayscale + A qint32 val; qint32 alpha; for (quint32 y = 0; y < bh.height; ++y) { QRgb* pixels = reinterpret_cast( pattern.scanLine(y) ); for (quint32 x = 0; x < bh.width; ++x, ++k) { if (k + 2 > dataSize) { qWarning() << "failed to load grayscale +_ alpha pattern" << filename(); return false; } val = data[k]; alpha = data[k++]; pixels[x] = qRgba(val, val, val, alpha); } } } else if (bh.bytes == 3) { // RGB without alpha for (quint32 y = 0; y < bh.height; ++y) { QRgb* pixels = reinterpret_cast( pattern.scanLine(y) ); for (quint32 x = 0; x < bh.width; ++x) { if (k + 3 > dataSize) { qWarning() << "failed to load RGB pattern" << filename(); return false; } pixels[x] = qRgb(data[k], data[k + 1], data[k + 2]); k += 3; } } } else if (bh.bytes == 4) { // Has alpha for (quint32 y = 0; y < bh.height; ++y) { QRgb* pixels = reinterpret_cast( pattern.scanLine(y) ); for (quint32 x = 0; x < bh.width; ++x) { if (k + 4 > dataSize) { qWarning() << "failed to load RGB + Alpha pattern" << filename(); return false; } pixels[x] = qRgba(data[k], data[k + 1], data[k + 2], data[k + 3]); k += 4; } } } else { return false; } if (pattern.isNull()) { return false; } setPatternImage(pattern); setValid(true); return true; } qint32 KoPattern::width() const { return m_pattern.width(); } qint32 KoPattern::height() const { return m_pattern.height(); } void KoPattern::setPatternImage(const QImage& image) { m_pattern = image; setImage(image); setValid(true); } KoPattern& KoPattern::operator=(const KoPattern & pattern) { setFilename(pattern.filename()); setPatternImage(pattern.pattern()); setValid(true); return *this; } QString KoPattern::defaultFileExtension() const { return QString(".pat"); } -KoPattern* KoPattern::clone() const +KoPatternSP KoPattern::clone() const { - KoPattern* pat = new KoPattern(filename()); + KoPatternSP pat(new KoPattern(filename())); pat->setPatternImage(pattern()); pat->setName(name()); return pat; } QImage KoPattern::pattern() const { return m_pattern; } diff --git a/libs/pigment/resources/KoPattern.h b/libs/pigment/resources/KoPattern.h index f82a0f2ae9..e1210de2a2 100644 --- a/libs/pigment/resources/KoPattern.h +++ b/libs/pigment/resources/KoPattern.h @@ -1,80 +1,86 @@ /* Copyright (c) 2000 Matthias Elter 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 KOPATTERN_H #define KOPATTERN_H #include #include #include +#include + +class KoPattern; +typedef QSharedPointer KoPatternSP; + /// Write API docs here class KRITAPIGMENT_EXPORT KoPattern : public KoResource { - public: /** * Creates a new KoPattern object using @p filename. No file is opened * in the constructor, you have to call load. * * @param filename the file name to save and load from. */ explicit KoPattern(const QString &filename); KoPattern(const QImage &image, const QString &name, const QString &folderName); ~KoPattern() override; public: bool load() override; bool loadFromDevice(QIODevice *dev) override; bool save() override; bool saveToDevice(QIODevice* dev) const override; bool loadPatFromDevice(QIODevice *dev); bool savePatToDevice(QIODevice* dev) const; qint32 width() const; qint32 height() const; QString defaultFileExtension() const override; KoPattern& operator=(const KoPattern& pattern); - KoPattern* clone() const; + KoPatternSP clone() const; /** * @brief pattern the actual pattern image * @return a valid QImage. There are no guarantees to the image format. */ QImage pattern() const; private: bool init(QByteArray& data); void setPatternImage(const QImage& image); private: QImage m_pattern; mutable QByteArray m_md5; }; Q_DECLARE_METATYPE(KoPattern*) +Q_DECLARE_METATYPE(QSharedPointer) + #endif // KOPATTERN_H diff --git a/libs/pigment/resources/KoSegmentGradient.cpp b/libs/pigment/resources/KoSegmentGradient.cpp index 05267b6877..b2b989aac2 100644 --- a/libs/pigment/resources/KoSegmentGradient.cpp +++ b/libs/pigment/resources/KoSegmentGradient.cpp @@ -1,982 +1,982 @@ /* 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 "KoColorSpaceRegistry.h" #include "KoColorSpace.h" #include "KoMixColorsOp.h" #include #include #include KoGradientSegment::RGBColorInterpolationStrategy *KoGradientSegment::RGBColorInterpolationStrategy::m_instance = 0; KoGradientSegment::HSVCWColorInterpolationStrategy *KoGradientSegment::HSVCWColorInterpolationStrategy::m_instance = 0; KoGradientSegment::HSVCCWColorInterpolationStrategy *KoGradientSegment::HSVCCWColorInterpolationStrategy::m_instance = 0; KoGradientSegment::LinearInterpolationStrategy *KoGradientSegment::LinearInterpolationStrategy::m_instance = 0; KoGradientSegment::CurvedInterpolationStrategy *KoGradientSegment::CurvedInterpolationStrategy::m_instance = 0; KoGradientSegment::SineInterpolationStrategy *KoGradientSegment::SineInterpolationStrategy::m_instance = 0; KoGradientSegment::SphereIncreasingInterpolationStrategy *KoGradientSegment::SphereIncreasingInterpolationStrategy::m_instance = 0; KoGradientSegment::SphereDecreasingInterpolationStrategy *KoGradientSegment::SphereDecreasingInterpolationStrategy::m_instance = 0; KoSegmentGradient::KoSegmentGradient(const QString& file) : KoAbstractGradient(file) { } KoSegmentGradient::~KoSegmentGradient() { for (int i = 0; i < m_segments.count(); i++) { delete m_segments[i]; m_segments[i] = 0; } } KoSegmentGradient::KoSegmentGradient(const KoSegmentGradient &rhs) : KoAbstractGradient(rhs) { Q_FOREACH (KoGradientSegment *segment, rhs.m_segments) { pushSegment(new KoGradientSegment(*segment)); } } -KoAbstractGradient* KoSegmentGradient::clone() const +KoAbstractGradientSP KoSegmentGradient::clone() const { - return new KoSegmentGradient(*this); + return KoAbstractGradientSP(new KoSegmentGradient(*this)); } bool KoSegmentGradient::load() { QFile file(filename()); if (!file.open(QIODevice::ReadOnly)) { warnPigment << "Can't open file " << filename(); return false; } bool res = loadFromDevice(&file); file.close(); return res; } bool KoSegmentGradient::loadFromDevice(QIODevice *dev) { QByteArray data = dev->readAll(); QTextStream fileContent(data, QIODevice::ReadOnly); fileContent.setAutoDetectUnicode(true); QString header = fileContent.readLine(); if (header != "GIMP Gradient") { return false; } QString nameDefinition = fileContent.readLine(); QString numSegmentsText; if (nameDefinition.startsWith("Name: ")) { QString nameText = nameDefinition.right(nameDefinition.length() - 6); setName(nameText); numSegmentsText = fileContent.readLine(); } else { // Older format without name. numSegmentsText = nameDefinition; } dbgPigment << "Loading gradient: " << name(); int numSegments; bool ok; numSegments = numSegmentsText.toInt(&ok); if (!ok || numSegments < 1) { return false; } dbgPigment << "Number of segments = " << numSegments; const KoColorSpace* rgbColorSpace = KoColorSpaceRegistry::instance()->rgb8(); for (int i = 0; i < numSegments; i++) { QString segmentText = fileContent.readLine(); QTextStream segmentFields(&segmentText); QStringList values = segmentText.split(' '); qreal leftOffset = values[0].toDouble(); qreal middleOffset = values[1].toDouble(); qreal rightOffset = values[2].toDouble(); qreal leftRed = values[3].toDouble(); qreal leftGreen = values[4].toDouble(); qreal leftBlue = values[5].toDouble(); qreal leftAlpha = values[6].toDouble(); qreal rightRed = values[7].toDouble(); qreal rightGreen = values[8].toDouble(); qreal rightBlue = values[9].toDouble(); qreal rightAlpha = values[10].toDouble(); int interpolationType = values[11].toInt(); int colorInterpolationType = values[12].toInt(); 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); KoGradientSegment *segment = new KoGradientSegment(interpolationType, colorInterpolationType, leftOffset, middleOffset, rightOffset, leftColor, rightColor); Q_CHECK_PTR(segment); if (!segment -> isValid()) { delete segment; return false; } m_segments.push_back(segment); } if (!m_segments.isEmpty()) { updatePreview(); setValid(true); return true; } else { return false; } } bool KoSegmentGradient::save() { QFile file(filename()); if (!file.open(QIODevice::WriteOnly)) { return false; } saveToDevice(&file); file.close(); return true; } bool KoSegmentGradient::saveToDevice(QIODevice *dev) const { QTextStream fileContent(dev); fileContent << "GIMP Gradient\n"; fileContent << "Name: " << name() << "\n"; fileContent << m_segments.count() << "\n"; Q_FOREACH (KoGradientSegment* segment, m_segments) { fileContent << QString::number(segment->startOffset(), 'f') << " " << QString::number(segment->middleOffset(), 'f') << " " << QString::number(segment->endOffset(), 'f') << " "; QColor startColor = segment->startColor().toQColor(); QColor endColor = segment->endColor().toQColor(); fileContent << QString::number(startColor.redF(), 'f') << " " << QString::number(startColor.greenF(), 'f') << " " << QString::number(startColor.blueF(), 'f') << " " << QString::number(startColor.alphaF(), 'f') << " "; fileContent << QString::number(endColor.redF(), 'f') << " " << QString::number(endColor.greenF(), 'f') << " " << QString::number(endColor.blueF(), 'f') << " " << QString::number(endColor.alphaF(), 'f') << " "; fileContent << (int)segment->interpolation() << " " << (int)segment->colorInterpolation() << "\n"; } KoResource::saveToDevice(dev); return true; } KoGradientSegment *KoSegmentGradient::segmentAt(qreal t) const { Q_ASSERT(t >= 0 || t <= 1); Q_ASSERT(!m_segments.empty()); 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); Q_ASSERT(segment != 0); 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", segment->startOffset()); const KoColor startColor = segment->startColor(); segmentElt.setAttribute("start-bitdepth", startColor.colorSpace()->colorDepthId().id()); segmentElt.setAttribute("start-alpha", startColor.opacityF()); startColor.toXML(doc, start); segmentElt.setAttribute("middle-offset", segment->middleOffset()); segmentElt.setAttribute("end-offset", segment->endOffset()); const KoColor endColor = segment->endColor(); segmentElt.setAttribute("end-bitdepth", endColor.colorSpace()->colorDepthId().id()); segmentElt.setAttribute("end-alpha", endColor.opacityF()); endColor.toXML(doc, end); segmentElt.setAttribute("interpolation", segment->interpolation()); segmentElt.setAttribute("color-interpolation", 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 = segmentElt.attribute("interpolation", "0.0").toInt(); int colorInterpolation = segmentElt.attribute("color-interpolation", "0.0").toInt(); double startOffset = segmentElt.attribute("start-offset", "0.0").toDouble(); qreal middleOffset = segmentElt.attribute("middle-offset", "0.0").toDouble(); qreal endOffset = segmentElt.attribute("end-offset", "0.0").toDouble(); QDomElement start = segmentElt.firstChildElement("start"); QString startBitdepth = segmentElt.attribute("start-bitdepth", Integer8BitsColorDepthID.id()); QColor left = KoColor::fromXML(start.firstChildElement(), startBitdepth).toQColor(); left.setAlphaF(segmentElt.attribute("start-alpha", "1.0").toDouble()); QString endBitdepth = segmentElt.attribute("end-bitdepth", Integer8BitsColorDepthID.id()); QDomElement end = segmentElt.firstChildElement("end"); QColor right = KoColor::fromXML(end.firstChildElement(), endBitdepth).toQColor(); right.setAlphaF(segmentElt.attribute("end-alpha", "1.0").toDouble()); gradient.createSegment(interpolation, colorInterpolation, startOffset, endOffset, middleOffset, left, right); segmentElt = segmentElt.nextSiblingElement("segment"); } return gradient; } KoGradientSegment::KoGradientSegment(int interpolationType, int colorInterpolationType, qreal startOffset, qreal middleOffset, qreal endOffset, const KoColor& startColor, const KoColor& endColor) { m_interpolator = 0; switch (interpolationType) { case INTERP_LINEAR: m_interpolator = LinearInterpolationStrategy::instance(); break; case INTERP_CURVED: m_interpolator = CurvedInterpolationStrategy::instance(); break; case INTERP_SINE: m_interpolator = SineInterpolationStrategy::instance(); break; case INTERP_SPHERE_INCREASING: m_interpolator = SphereIncreasingInterpolationStrategy::instance(); break; case INTERP_SPHERE_DECREASING: m_interpolator = SphereDecreasingInterpolationStrategy::instance(); break; } m_colorInterpolator = 0; switch (colorInterpolationType) { case COLOR_INTERP_RGB: m_colorInterpolator = RGBColorInterpolationStrategy::instance(); break; case COLOR_INTERP_HSV_CCW: m_colorInterpolator = HSVCCWColorInterpolationStrategy::instance(); break; case COLOR_INTERP_HSV_CW: m_colorInterpolator = HSVCWColorInterpolationStrategy::instance(); break; } if (startOffset < DBL_EPSILON) { m_startOffset = 0; } else if (startOffset > 1 - DBL_EPSILON) { m_startOffset = 1; } else { m_startOffset = startOffset; } if (middleOffset < m_startOffset + DBL_EPSILON) { m_middleOffset = m_startOffset; } else if (middleOffset > 1 - DBL_EPSILON) { m_middleOffset = 1; } else { m_middleOffset = middleOffset; } if (endOffset < m_middleOffset + DBL_EPSILON) { m_endOffset = m_middleOffset; } else if (endOffset > 1 - DBL_EPSILON) { m_endOffset = 1; } else { m_endOffset = endOffset; } m_length = m_endOffset - m_startOffset; if (m_length < DBL_EPSILON) { m_middleT = 0.5; } else { m_middleT = (m_middleOffset - m_startOffset) / m_length; } m_startColor = startColor; m_endColor = endColor; } const KoColor& KoGradientSegment::startColor() const { return m_startColor; } const KoColor& KoGradientSegment::endColor() const { return m_endColor; } qreal KoGradientSegment::startOffset() const { return m_startOffset; } qreal KoGradientSegment::middleOffset() const { return m_middleOffset; } qreal KoGradientSegment::endOffset() const { return m_endOffset; } void KoGradientSegment::setStartOffset(qreal t) { m_startOffset = t; m_length = m_endOffset - m_startOffset; if (m_length < DBL_EPSILON) { m_middleT = 0.5; } else { m_middleT = (m_middleOffset - m_startOffset) / m_length; } } void KoGradientSegment::setMiddleOffset(qreal t) { m_middleOffset = t; if (m_length < DBL_EPSILON) { m_middleT = 0.5; } else { m_middleT = (m_middleOffset - m_startOffset) / m_length; } } void KoGradientSegment::setEndOffset(qreal t) { m_endOffset = t; m_length = m_endOffset - m_startOffset; if (m_length < DBL_EPSILON) { m_middleT = 0.5; } else { m_middleT = (m_middleOffset - m_startOffset) / m_length; } } int KoGradientSegment::interpolation() const { return m_interpolator->type(); } void KoGradientSegment::setInterpolation(int interpolationType) { switch (interpolationType) { case INTERP_LINEAR: m_interpolator = LinearInterpolationStrategy::instance(); break; case INTERP_CURVED: m_interpolator = CurvedInterpolationStrategy::instance(); break; case INTERP_SINE: m_interpolator = SineInterpolationStrategy::instance(); break; case INTERP_SPHERE_INCREASING: m_interpolator = SphereIncreasingInterpolationStrategy::instance(); break; case INTERP_SPHERE_DECREASING: m_interpolator = SphereDecreasingInterpolationStrategy::instance(); break; } } int KoGradientSegment::colorInterpolation() const { return m_colorInterpolator->type(); } void KoGradientSegment::setColorInterpolation(int colorInterpolationType) { switch (colorInterpolationType) { case COLOR_INTERP_RGB: m_colorInterpolator = RGBColorInterpolationStrategy::instance(); break; case COLOR_INTERP_HSV_CCW: m_colorInterpolator = HSVCCWColorInterpolationStrategy::instance(); break; case COLOR_INTERP_HSV_CW: m_colorInterpolator = HSVCWColorInterpolationStrategy::instance(); break; } } void KoGradientSegment::colorAt(KoColor& dst, qreal t) const { Q_ASSERT(t > m_startOffset - DBL_EPSILON && t < m_endOffset + DBL_EPSILON); qreal segmentT; if (m_length < DBL_EPSILON) { segmentT = 0.5; } else { segmentT = (t - m_startOffset) / m_length; } qreal colorT = m_interpolator->valueAt(segmentT, m_middleT); m_colorInterpolator->colorAt(dst, colorT, m_startColor, m_endColor); } bool KoGradientSegment::isValid() const { if (m_interpolator == 0 || m_colorInterpolator == 0) return false; return true; } KoGradientSegment::RGBColorInterpolationStrategy::RGBColorInterpolationStrategy() : m_colorSpace(KoColorSpaceRegistry::instance()->rgb8()) { } KoGradientSegment::RGBColorInterpolationStrategy *KoGradientSegment::RGBColorInterpolationStrategy::instance() { if (m_instance == 0) { m_instance = new RGBColorInterpolationStrategy(); Q_CHECK_PTR(m_instance); } return m_instance; } void KoGradientSegment::RGBColorInterpolationStrategy::colorAt(KoColor& dst, qreal t, const KoColor& _start, const KoColor& _end) const { KoColor buffer(m_colorSpace); KoColor start(m_colorSpace); KoColor end(m_colorSpace); KoColor startDummy, endDummy; //hack to get a color space with the bitdepth of the gradients(8bit), but with the colour profile of the image// const KoColorSpace* mixSpace = KoColorSpaceRegistry::instance()->rgb8(dst.colorSpace()->profile()); //convert to the right colorspace for the start and end if we have our mixSpace. if (mixSpace){ startDummy = KoColor(_start, mixSpace); endDummy = KoColor(_end, mixSpace); } else { startDummy = _start; endDummy = _end; } start.fromKoColor(_start); end.fromKoColor(_end); const quint8 *colors[2]; colors[0] = startDummy.data(); colors[1] = endDummy.data(); qint16 colorWeights[2]; colorWeights[0] = static_cast((1.0 - t) * 255 + 0.5); colorWeights[1] = 255 - colorWeights[0]; //check if our mixspace exists, it doesn't at startup. if (mixSpace){ if (*buffer.colorSpace() != *mixSpace) { buffer = KoColor(mixSpace); } mixSpace->mixColorsOp()->mixColors(colors, colorWeights, 2, buffer.data()); } else { buffer = KoColor(m_colorSpace); m_colorSpace->mixColorsOp()->mixColors(colors, colorWeights, 2, buffer.data()); } dst.fromKoColor(buffer); } KoGradientSegment::HSVCWColorInterpolationStrategy::HSVCWColorInterpolationStrategy() : m_colorSpace(KoColorSpaceRegistry::instance()->rgb8()) { } KoGradientSegment::HSVCWColorInterpolationStrategy *KoGradientSegment::HSVCWColorInterpolationStrategy::instance() { if (m_instance == 0) { m_instance = new HSVCWColorInterpolationStrategy(); Q_CHECK_PTR(m_instance); } return m_instance; } void KoGradientSegment::HSVCWColorInterpolationStrategy::colorAt(KoColor& dst, qreal t, const KoColor& start, const KoColor& end) const { QColor sc; QColor ec; start.toQColor(&sc); end.toQColor(&ec); int s = static_cast(sc.saturation() + t * (ec.saturation() - sc.saturation()) + 0.5); int v = static_cast(sc.value() + t * (ec.value() - sc.value()) + 0.5); int h; if (ec.hue() < sc.hue()) { h = static_cast(ec.hue() + (1 - t) * (sc.hue() - ec.hue()) + 0.5); } else { h = static_cast(ec.hue() + (1 - t) * (360 - ec.hue() + sc.hue()) + 0.5); if (h > 359) { h -= 360; } } // XXX: added an explicit cast. Is this correct? quint8 opacity = static_cast(sc.alpha() + t * (ec.alpha() - sc.alpha())); QColor result; result.setHsv(h, s, v); result.setAlpha(opacity); dst.fromQColor(result); } KoGradientSegment::HSVCCWColorInterpolationStrategy::HSVCCWColorInterpolationStrategy() : m_colorSpace(KoColorSpaceRegistry::instance()->rgb8()) { } KoGradientSegment::HSVCCWColorInterpolationStrategy *KoGradientSegment::HSVCCWColorInterpolationStrategy::instance() { if (m_instance == 0) { m_instance = new HSVCCWColorInterpolationStrategy(); Q_CHECK_PTR(m_instance); } return m_instance; } void KoGradientSegment::HSVCCWColorInterpolationStrategy::colorAt(KoColor& dst, qreal t, const KoColor& start, const KoColor& end) const { QColor sc; QColor se; start.toQColor(&sc); end.toQColor(&se); int s = static_cast(sc.saturation() + t * (se.saturation() - sc.saturation()) + 0.5); int v = static_cast(sc.value() + t * (se.value() - sc.value()) + 0.5); int h; if (sc.hue() < se.hue()) { h = static_cast(sc.hue() + t * (se.hue() - sc.hue()) + 0.5); } else { h = static_cast(sc.hue() + t * (360 - sc.hue() + se.hue()) + 0.5); if (h > 359) { h -= 360; } } // XXX: Added an explicit static cast quint8 opacity = static_cast(sc.alpha() + t * (se.alpha() - sc.alpha())); QColor result; result.setHsv(h, s, v); result.setAlpha(opacity); dst.fromQColor(result); } KoGradientSegment::LinearInterpolationStrategy *KoGradientSegment::LinearInterpolationStrategy::instance() { if (m_instance == 0) { m_instance = new LinearInterpolationStrategy(); Q_CHECK_PTR(m_instance); } return m_instance; } qreal KoGradientSegment::LinearInterpolationStrategy::calcValueAt(qreal t, qreal middle) { Q_ASSERT(t > -DBL_EPSILON && t < 1 + DBL_EPSILON); Q_ASSERT(middle > -DBL_EPSILON && middle < 1 + DBL_EPSILON); qreal value = 0; if (t <= middle) { if (middle < DBL_EPSILON) { value = 0; } else { value = (t / middle) * 0.5; } } else { if (middle > 1 - DBL_EPSILON) { value = 1; } else { value = ((t - middle) / (1 - middle)) * 0.5 + 0.5; } } return value; } qreal KoGradientSegment::LinearInterpolationStrategy::valueAt(qreal t, qreal middle) const { return calcValueAt(t, middle); } KoGradientSegment::CurvedInterpolationStrategy::CurvedInterpolationStrategy() { m_logHalf = log(0.5); } KoGradientSegment::CurvedInterpolationStrategy *KoGradientSegment::CurvedInterpolationStrategy::instance() { if (m_instance == 0) { m_instance = new CurvedInterpolationStrategy(); Q_CHECK_PTR(m_instance); } return m_instance; } qreal KoGradientSegment::CurvedInterpolationStrategy::valueAt(qreal t, qreal middle) const { Q_ASSERT(t > -DBL_EPSILON && t < 1 + DBL_EPSILON); Q_ASSERT(middle > -DBL_EPSILON && middle < 1 + DBL_EPSILON); qreal value = 0; if (middle < DBL_EPSILON) { middle = DBL_EPSILON; } value = pow(t, m_logHalf / log(middle)); return value; } KoGradientSegment::SineInterpolationStrategy *KoGradientSegment::SineInterpolationStrategy::instance() { if (m_instance == 0) { m_instance = new SineInterpolationStrategy(); Q_CHECK_PTR(m_instance); } return m_instance; } qreal KoGradientSegment::SineInterpolationStrategy::valueAt(qreal t, qreal middle) const { qreal lt = LinearInterpolationStrategy::calcValueAt(t, middle); qreal value = (sin(-M_PI_2 + M_PI * lt) + 1.0) / 2.0; return value; } KoGradientSegment::SphereIncreasingInterpolationStrategy *KoGradientSegment::SphereIncreasingInterpolationStrategy::instance() { if (m_instance == 0) { m_instance = new SphereIncreasingInterpolationStrategy(); Q_CHECK_PTR(m_instance); } return m_instance; } qreal KoGradientSegment::SphereIncreasingInterpolationStrategy::valueAt(qreal t, qreal middle) const { qreal lt = LinearInterpolationStrategy::calcValueAt(t, middle) - 1; qreal value = sqrt(1 - lt * lt); return value; } KoGradientSegment::SphereDecreasingInterpolationStrategy *KoGradientSegment::SphereDecreasingInterpolationStrategy::instance() { if (m_instance == 0) { m_instance = new SphereDecreasingInterpolationStrategy(); Q_CHECK_PTR(m_instance); } return m_instance; } qreal KoGradientSegment::SphereDecreasingInterpolationStrategy::valueAt(qreal t, qreal middle) const { qreal lt = LinearInterpolationStrategy::calcValueAt(t, middle); qreal value = 1 - sqrt(1 - lt * lt); return value; } void KoSegmentGradient::createSegment(int interpolation, int colorInterpolation, double startOffset, double endOffset, double middleOffset, const QColor & left, const QColor & right) { pushSegment(new KoGradientSegment(interpolation, colorInterpolation, startOffset, middleOffset, endOffset, KoColor(left, colorSpace()), KoColor(right, colorSpace()))); } 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()); KoGradientSegment* newSegment = new KoGradientSegment( segment->interpolation(), segment->colorInterpolation(), segment ->startOffset(), (segment->middleOffset() - segment->startOffset()) / 2 + segment->startOffset(), segment->middleOffset(), segment->startColor(), midleoffsetColor); 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; KoGradientSegment* newSegment = new KoGradientSegment( segment->interpolation(), segment->colorInterpolation(), segment ->startOffset(), segment->length() / 2 * middlePostionPercentage + segment->startOffset(), center, segment->startColor(), segment->endColor()); m_segments.insert(it, newSegment); segment->setStartOffset(center); segment->setMiddleOffset(segment->length() * middlePostionPercentage + segment->startOffset()); } } void KoSegmentGradient::mirrorSegment(KoGradientSegment* segment) { Q_ASSERT(segment != 0); KoColor tmpColor = segment->startColor(); segment->setStartColor(segment->endColor()); segment->setEndColor(tmpColor); segment->setMiddleOffset(segment->endOffset() - (segment->middleOffset() - segment->startOffset())); if (segment->interpolation() == INTERP_SPHERE_INCREASING) segment->setInterpolation(INTERP_SPHERE_DECREASING); else if (segment->interpolation() == INTERP_SPHERE_DECREASING) segment->setInterpolation(INTERP_SPHERE_INCREASING); 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; } diff --git a/libs/pigment/resources/KoSegmentGradient.h b/libs/pigment/resources/KoSegmentGradient.h index f467ed4658..1f64cb8abe 100644 --- a/libs/pigment/resources/KoSegmentGradient.h +++ b/libs/pigment/resources/KoSegmentGradient.h @@ -1,431 +1,433 @@ /* 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 }; /// Write API docs here class KRITAPIGMENT_EXPORT KoGradientSegment { public: KoGradientSegment(int interpolationType, int colorInterpolationType, qreal startOffset, qreal middleOffset, qreal endOffset, const KoColor& startColor, const KoColor& endColor); // startOffset <= t <= endOffset void colorAt(KoColor&, qreal t) const; const KoColor& startColor() const; const KoColor& endColor() const; void setStartColor(const KoColor& color) { m_startColor = color; } void setEndColor(const KoColor& color) { m_endColor = color; } qreal startOffset() const; qreal middleOffset() const; qreal endOffset() const; void setStartOffset(qreal t); void setMiddleOffset(qreal t); void setEndOffset(qreal t); qreal length() { return m_length; } int interpolation() const; int colorInterpolation() const; void setInterpolation(int interpolationType); void setColorInterpolation(int colorInterpolationType); 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; }; /** * KoSegmentGradient stores a segment based gradients like Gimp gradients */ class KRITAPIGMENT_EXPORT KoSegmentGradient : public KoAbstractGradient { public: explicit KoSegmentGradient(const QString &file = QString()); ~KoSegmentGradient() override; - KoAbstractGradient* clone() const override; + KoAbstractGradientSP clone() const override; /// reimplemented bool load() override; bool loadFromDevice(QIODevice *dev) override; /// not implemented bool save() override; bool saveToDevice(QIODevice* dev) const override; /// reimplemented void colorAt(KoColor& dst, qreal t) const override; /** * 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 * @return void */ void createSegment(int interpolation, int colorInterpolation, double startOffset, double endOffset, double middleOffset, const QColor & left, const QColor & right); /** * gets a list of end points of the segments in the gradient * colour picker. If two colours, one segment then two end * points, and if three colours, then two segments with four * endpoints. * @return a list of double values */ const QList getHandlePositions() const; /** * gets a list of middle points of the segments in the gradient * colour picker. * @return a list of double values */ const QList getMiddleHandlePositions() const; /** * Moves the StartOffset of the specified segment to the * specified value and corrects the endoffset of the previous * segment. If the segment is the first Segment the startoffset * will be set to 0.0 . The offset will maximally be moved till * the middle of the current or the previous segment. This is * useful if someone clicks to move the handler for a segment, * to set the half the segment to the right and half the segment * to the left of the handler. * @param segment the segment for which to move the relative * offset within the gradient colour picker. * @param t the new startoff position for the segment * @return void */ void moveSegmentStartOffset(KoGradientSegment* segment, double t); /** * Moves the endoffset of the specified segment to the specified * value and corrects the startoffset of the following segment. * If the segment is the last segment the endoffset will be set * to 1.0 . The offset will maximally be moved till the middle * of the current or the following segment. This is useful if * someone moves the segment handler in the gradient colour * picker, and needs the segment to move with it. Sets the end * position of the segment to the correct new position. * @param segment the segment for which to move the relative * end position within the gradient colour picker. * @param t the new end position for the segment * @return void */ void moveSegmentEndOffset(KoGradientSegment* segment, double t); /** * moves the Middle of the specified segment to the specified * value. The offset will maximally be moved till the endoffset * or startoffset of the segment. This sets the middle of the * segment to the same position as the handler of the gradient * colour picker. * @param segment the segment for which to move the relative * middle position within the gradient colour picker. * @param t the new middle position for the segment * @return void */ void moveSegmentMiddleOffset(KoGradientSegment* segment, double t); /** * splits the specified segment into two equal parts * @param segment the segment to split * @return void */ void splitSegment(KoGradientSegment* segment); /** * duplicate the specified segment * @param segment the segment to duplicate * @return void */ void duplicateSegment(KoGradientSegment* segment); /** * create a segment horizontally reversed to the specified one. * @param segment the segment to reverse * @return void */ void mirrorSegment(KoGradientSegment* segment); /** * removes the specific segment from the gradient colour picker. * @param segment the segment to remove * @return the segment which will be at the place of the old * segment. 0 if the segment is not in the gradient or it is * not possible to remove the segment. */ KoGradientSegment* removeSegment(KoGradientSegment* segment); /** * checks if it's possible to remove a segment (at least two * segments in the gradient) * @return true if it's possible to remove an segment */ bool removeSegmentPossible() const; const QList& segments() const; protected: KoSegmentGradient(const KoSegmentGradient &rhs); inline void pushSegment(KoGradientSegment* segment) { m_segments.push_back(segment); } QList m_segments; private: bool init(); }; +typedef QSharedPointer KoSegmentGradientSP; + #endif // KOSEGMENTGRADIENT_H diff --git a/libs/pigment/resources/KoStopGradient.cpp b/libs/pigment/resources/KoStopGradient.cpp index 3d185dff6f..862e49c098 100644 --- a/libs/pigment/resources/KoStopGradient.cpp +++ b/libs/pigment/resources/KoStopGradient.cpp @@ -1,730 +1,729 @@ /* 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 #include KoStopGradient::KoStopGradient(const QString& filename) : KoAbstractGradient(filename) { } KoStopGradient::~KoStopGradient() { } bool KoStopGradient::operator==(const KoStopGradient &rhs) const { return *colorSpace() == *rhs.colorSpace() && spread() == rhs.spread() && type() == rhs.type() && m_start == rhs.m_start && m_stop == rhs.m_stop && m_focalPoint == rhs.m_focalPoint && m_stops == rhs.m_stops; } -KoAbstractGradient* KoStopGradient::clone() const +KoAbstractGradientSP KoStopGradient::clone() const { - return new KoStopGradient(*this); + return KoAbstractGradientSP(new KoStopGradient(*this)); } bool KoStopGradient::load() { QFile f(filename()); if (!f.open(QIODevice::ReadOnly)) { warnPigment << "Can't open file " << filename(); return false; } bool res = loadFromDevice(&f); f.close(); return res; } bool KoStopGradient::loadFromDevice(QIODevice *dev) { QString strExt; const int result = filename().lastIndexOf('.'); if (result >= 0) { strExt = filename().mid(result).toLower(); } QByteArray ba = dev->readAll(); QBuffer buf(&ba); if (strExt == ".kgr") { loadKarbonGradient(&buf); } else if (strExt == ".svg") { loadSvgGradient(&buf); } if (m_stops.count() >= 2) { setValid(true); } updatePreview(); return true; } bool KoStopGradient::save() { QFile fileOut(filename()); if (! fileOut.open(QIODevice::WriteOnly)) return false; bool retval = saveToDevice(&fileOut); fileOut.close(); return retval; } QGradient* KoStopGradient::toQGradient() const { QGradient* gradient; switch (type()) { case QGradient::LinearGradient: { gradient = new QLinearGradient(m_start, m_stop); break; } case QGradient::RadialGradient: { QPointF diff = m_stop - m_start; qreal radius = sqrt(diff.x() * diff.x() + diff.y() * diff.y()); gradient = new QRadialGradient(m_start, radius, m_focalPoint); break; } case QGradient::ConicalGradient: { qreal angle = atan2(m_start.y(), m_start.x()) * 180.0 / M_PI; if (angle < 0.0) angle += 360.0; gradient = new QConicalGradient(m_start, angle); break; } default: return 0; } QColor color; for (QList::const_iterator i = m_stops.begin(); i != m_stops.end(); ++i) { i->second.toQColor(&color); gradient->setColorAt(i->first , color); } gradient->setCoordinateMode(QGradient::ObjectBoundingMode); gradient->setSpread(this->spread()); return gradient; } void KoStopGradient::colorAt(KoColor& dst, qreal t) const { KoColor buffer; if (! m_stops.count()) return; if (t <= m_stops.first().first || m_stops.count() == 1) { // we have only one stop or t is before the first stop // -> use the color of the first stop dst.fromKoColor(m_stops.first().second); } else if (t >= m_stops.last().first) { // t is after the last stop // -> use the color of the last stop dst.fromKoColor(m_stops.last().second); } else { // we have at least two color stops // -> find the two stops which frame our t QList::const_iterator stop = m_stops.begin(); QList::const_iterator lastStop = m_stops.end(); // we already checked the first stop, so we start at the second for (++stop; stop != lastStop; ++stop) { // we break at the stop which is just after our t if (stop->first > t) break; } //if ( *buffer.colorSpace() != *colorSpace()) { // buffer = KoColor(colorSpace()); //} //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()); const KoGradientStop& leftStop = *(stop - 1); const KoGradientStop& rightStop = *(stop); KoColor startDummy, endDummy; if (mixSpace){ startDummy = KoColor(leftStop.second, mixSpace); endDummy = KoColor(rightStop.second, mixSpace); } else { startDummy = leftStop.second; endDummy = rightStop.second; } const quint8 *colors[2]; colors[0] = startDummy.data(); colors[1] = endDummy.data(); qreal localT; qreal stopDistance = rightStop.first - leftStop.first; if (stopDistance < DBL_EPSILON) { localT = 0.5; } else { localT = (t - leftStop.first) / stopDistance; } qint16 colorWeights[2]; colorWeights[0] = static_cast((1.0 - localT) * 255 + 0.5); colorWeights[1] = 255 - colorWeights[0]; //check if our mixspace exists, it doesn't at startup. if (mixSpace){ if (*buffer.colorSpace() != *mixSpace) { buffer = KoColor(mixSpace); } mixSpace->mixColorsOp()->mixColors(colors, colorWeights, 2, buffer.data()); } else { buffer = KoColor(colorSpace()); colorSpace()->mixColorsOp()->mixColors(colors, colorWeights, 2, buffer.data()); } dst.fromKoColor(buffer); } } -KoStopGradient * KoStopGradient::fromQGradient(const QGradient * gradient) +QSharedPointer KoStopGradient::fromQGradient(const QGradient *gradient) { if (! gradient) - return 0; + return QSharedPointer(0); - KoStopGradient * newGradient = new KoStopGradient(QString()); + 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: - delete newGradient; - return 0; + 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, color)); } newGradient->setValid(true); return newGradient; } void KoStopGradient::setStops(QList< KoGradientStop > stops) { m_stops.clear(); KoColor color; Q_FOREACH (const KoGradientStop & stop, stops) { color = stop.second; color.convertTo(colorSpace()); m_stops.append(KoGradientStop(stop.first, color)); } updatePreview(); } QList KoStopGradient::stops() const { return m_stops; } void KoStopGradient::loadKarbonGradient(QIODevice *file) { QDomDocument doc; if (!(doc.setContent(file))) { file->close(); setValid(false); return; } QDomElement e; QDomNode n = doc.documentElement().firstChild(); if (!n.isNull()) { e = n.toElement(); if (!e.isNull() && e.tagName() == "GRADIENT") { parseKarbonGradient(e); } } } 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::parseKarbonGradient(const QDomElement& element) { m_start = QPointF(element.attribute("originX", "0.0").toDouble(), element.attribute("originY", "0.0").toDouble()); m_focalPoint = QPointF(element.attribute("focalX", "0.0").toDouble(), element.attribute("focalY", "0.0").toDouble()); m_stop = QPointF(element.attribute("vectorX", "0.0").toDouble(), element.attribute("vectorY", "0.0").toDouble()); setType((QGradient::Type)element.attribute("type", 0).toInt()); setSpread((QGradient::Spread)element.attribute("repeatMethod", 0).toInt()); m_stops.clear(); qreal color1, color2, color3, color4, opacity; KoColor color; // load stops QDomNodeList list = element.childNodes(); for (int i = 0; i < list.count(); ++i) { if (list.item(i).isElement()) { QDomElement colorstop = list.item(i).toElement(); if (colorstop.tagName() == "COLORSTOP") { QDomElement e = colorstop.firstChild().toElement(); opacity = e.attribute("opacity", "1.0").toFloat(); QColor tmpColor; const KoColorSpace* stopColorSpace; switch (e.attribute("colorSpace").toUShort()) { case 1: // cmyk color1 = e.attribute("v1", "0.0").toFloat(); color2 = e.attribute("v2", "0.0").toFloat(); color3 = e.attribute("v3", "0.0").toFloat(); color4 = e.attribute("v4", "0.0").toFloat(); stopColorSpace = KoColorSpaceRegistry::instance()->colorSpace( CMYKAColorModelID.id(), Integer8BitsColorDepthID.id(), QString()); if (stopColorSpace) { quint8 data[5]; data[0] = static_cast(color1 * 255 + 0.5); data[1] = static_cast(color2 * 255 + 0.5); data[2] = static_cast(color3 * 255 + 0.5); data[3] = static_cast(color4 * 255 + 0.5); data[4] = static_cast(opacity * OPACITY_OPAQUE_U8 + 0.5); color.setColor(data, stopColorSpace); } else { // cmyk colorspace not found fallback to rgb color.convertTo(KoColorSpaceRegistry::instance()->rgb8()); tmpColor.setCmykF(color1, color2, color3, color4); tmpColor.setAlpha(static_cast(opacity * OPACITY_OPAQUE_U8 + 0.5)); color.fromQColor(tmpColor); } break; case 2: // hsv color1 = e.attribute("v1", "0.0").toFloat(); color2 = e.attribute("v2", "0.0").toFloat(); color3 = e.attribute("v3", "0.0").toFloat(); color.convertTo(KoColorSpaceRegistry::instance()->rgb8()); tmpColor.setHsvF(color1, color2, color3); tmpColor.setAlpha(static_cast(opacity * OPACITY_OPAQUE_U8 + 0.5)); color.fromQColor(tmpColor); break; case 3: // gray color1 = e.attribute("v1", "0.0").toFloat(); stopColorSpace = KoColorSpaceRegistry::instance()->colorSpace( GrayAColorModelID.id(), Integer8BitsColorDepthID.id(), QString()); if (stopColorSpace) { quint8 data[2]; data[0] = static_cast(color1 * 255 + 0.5); data[1] = static_cast(opacity * OPACITY_OPAQUE_U8 + 0.5); color.setColor(data, stopColorSpace); } else { // gray colorspace not found fallback to rgb color.convertTo(KoColorSpaceRegistry::instance()->rgb8()); tmpColor.setRgbF(color1, color1, color1); tmpColor.setAlpha(static_cast(opacity * OPACITY_OPAQUE_U8 + 0.5)); color.fromQColor(tmpColor); } break; default: // rgb color1 = e.attribute("v1", "0.0").toFloat(); color2 = e.attribute("v2", "0.0").toFloat(); color3 = e.attribute("v3", "0.0").toFloat(); stopColorSpace = KoColorSpaceRegistry::instance()->rgb8(); quint8 data[4]; data[2] = static_cast(color1 * 255 + 0.5); data[1] = static_cast(color2 * 255 + 0.5); data[0] = static_cast(color3 * 255 + 0.5); data[3] = static_cast(opacity * OPACITY_OPAQUE_U8 + 0.5); color.setColor(data, stopColorSpace); } qreal offset = colorstop.attribute("ramppoint", "0.0").toFloat(); // midpoint = colorstop.attribute("midpoint", "0.5").toFloat(); m_stops.append(KoGradientStop(offset, color)); } } } } 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)); //According to the SVG spec each gradient offset has to be equal to or greater than the previous one //if not it needs to be adjusted to be equal if (m_stops.count() > 0 && m_stops.last().first >= off) { off = m_stops.last().first; } m_stops.append(KoGradientStop(off, color)); } } } 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; scolorDepthId().id()); stopElt.setAttribute("alpha", stop.second.opacityF()); stop.second.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 = stopElt.attribute("offset", "0").toDouble(); QString bitDepth = stopElt.attribute("bitdepth", Integer8BitsColorDepthID.id()); KoColor color = KoColor::fromXML(stopElt.firstChildElement(), bitDepth); color.setOpacity(stopElt.attribute("alpha", "1.0").toDouble()); stops.append(KoGradientStop(offset, color)); 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.toQColor(&color); stream << indent << indent; stream << "(color.alpha()) / 255.0f << "\"" << " />" << 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 9b8bac53fb..c01e3db7f0 100644 --- a/libs/pigment/resources/KoStopGradient.h +++ b/libs/pigment/resources/KoStopGradient.h @@ -1,97 +1,99 @@ /* 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 "KoColor.h" #include #include #include #include typedef QPair KoGradientStop; /** * Resource for colorstop based gradients like Karbon gradients and SVG gradients */ class KRITAPIGMENT_EXPORT KoStopGradient : public KoAbstractGradient, public boost::equality_comparable { public: explicit KoStopGradient(const QString &filename = QString()); ~KoStopGradient() override; bool operator==(const KoStopGradient &rhs) const; - KoAbstractGradient* clone() const override; + KoAbstractGradientSP clone() const override; bool load() override; bool loadFromDevice(QIODevice *dev) override; bool save() override; bool saveToDevice(QIODevice* dev) const override; /// reimplemented QGradient* toQGradient() const override; /// reimplemented void colorAt(KoColor&, qreal t) const override; /// Creates KoStopGradient from a QGradient - static KoStopGradient * fromQGradient(const QGradient * gradient); + static QSharedPointer fromQGradient(const QGradient *gradient); /// Sets the gradient stops void setStops(QList stops); QList stops() const; /// 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; QPointF m_start; QPointF m_stop; QPointF m_focalPoint; private: void loadKarbonGradient(QIODevice *file); void parseKarbonGradient(const QDomElement& element); 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_callback_object_catcher.cpp b/libs/psd/asl/kis_asl_callback_object_catcher.cpp index 3a7f7057cb..f1437aa3a4 100644 --- a/libs/psd/asl/kis_asl_callback_object_catcher.cpp +++ b/libs/psd/asl/kis_asl_callback_object_catcher.cpp @@ -1,258 +1,258 @@ /* * 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_callback_object_catcher.h" #include #include #include #include #include "kis_debug.h" typedef QHash MapHashDouble; typedef QHash MapHashInt; struct EnumMapping { EnumMapping(const QString &_typeId, ASLCallbackString _map) : typeId(_typeId), map(_map) { } QString typeId; ASLCallbackString map; }; typedef QHash MapHashEnum; struct UnitFloatMapping { UnitFloatMapping(const QString &_unit, ASLCallbackDouble _map) : unit(_unit), map(_map) { } QString unit; ASLCallbackDouble map; }; typedef QHash MapHashUnitFloat; typedef QHash MapHashText; typedef QHash MapHashBoolean; typedef QHash MapHashColor; typedef QHash MapHashPoint; typedef QHash MapHashCurve; typedef QHash MapHashPattern; typedef QHash MapHashPatternRef; typedef QHash MapHashGradient; struct KisAslCallbackObjectCatcher::Private { MapHashDouble mapDouble; MapHashInt mapInteger; MapHashEnum mapEnum; MapHashUnitFloat mapUnitFloat; MapHashText mapText; MapHashBoolean mapBoolean; MapHashColor mapColor; MapHashPoint mapPoint; MapHashCurve mapCurve; MapHashPattern mapPattern; MapHashPatternRef mapPatternRef; MapHashGradient mapGradient; ASLCallbackNewStyle newStyleCallback; }; KisAslCallbackObjectCatcher::KisAslCallbackObjectCatcher() : m_d(new Private) { } KisAslCallbackObjectCatcher::~KisAslCallbackObjectCatcher() { } template inline void passToCallback(const QString &path, const HashType &hash, const T &value) { typename HashType::const_iterator it = hash.constFind(path); if (it != hash.constEnd()) { (*it)(value); } } void KisAslCallbackObjectCatcher::addDouble(const QString &path, double value) { passToCallback(path, m_d->mapDouble, value); } void KisAslCallbackObjectCatcher::addInteger(const QString &path, int value) { passToCallback(path, m_d->mapInteger, value); } void KisAslCallbackObjectCatcher::addEnum(const QString &path, const QString &typeId, const QString &value) { MapHashEnum::const_iterator it = m_d->mapEnum.constFind(path); if (it != m_d->mapEnum.constEnd()) { if (it->typeId == typeId) { it->map(value); } else { warnKrita << "KisAslCallbackObjectCatcher::addEnum: inconsistent typeId" << ppVar(typeId) << ppVar(it->typeId); } } } void KisAslCallbackObjectCatcher::addUnitFloat(const QString &path, const QString &unit, double value) { MapHashUnitFloat::const_iterator it = m_d->mapUnitFloat.constFind(path); if (it != m_d->mapUnitFloat.constEnd()) { if (it->unit == unit) { it->map(value); } else { warnKrita << "KisAslCallbackObjectCatcher::addUnitFloat: inconsistent unit" << ppVar(unit) << ppVar(it->unit); } } } void KisAslCallbackObjectCatcher::addText(const QString &path, const QString &value) { passToCallback(path, m_d->mapText, value); } void KisAslCallbackObjectCatcher::addBoolean(const QString &path, bool value) { passToCallback(path, m_d->mapBoolean, value); } void KisAslCallbackObjectCatcher::addColor(const QString &path, const QColor &value) { passToCallback(path, m_d->mapColor, value); } void KisAslCallbackObjectCatcher::addPoint(const QString &path, const QPointF &value) { passToCallback(path, m_d->mapPoint, value); } void KisAslCallbackObjectCatcher::addCurve(const QString &path, const QString &name, const QVector &points) { MapHashCurve::const_iterator it = m_d->mapCurve.constFind(path); if (it != m_d->mapCurve.constEnd()) { (*it)(name, points); } } -void KisAslCallbackObjectCatcher::addPattern(const QString &path, const KoPattern *value) +void KisAslCallbackObjectCatcher::addPattern(const QString &path, const KoPatternSP value) { passToCallback(path, m_d->mapPattern, value); } void KisAslCallbackObjectCatcher::addPatternRef(const QString &path, const QString &patternUuid, const QString &patternName) { MapHashPatternRef::const_iterator it = m_d->mapPatternRef.constFind(path); if (it != m_d->mapPatternRef.constEnd()) { (*it)(patternUuid, patternName); } } void KisAslCallbackObjectCatcher::addGradient(const QString &path, KoAbstractGradientSP value) { passToCallback(path, m_d->mapGradient, value); } void KisAslCallbackObjectCatcher::newStyleStarted() { if (m_d->newStyleCallback) { m_d->newStyleCallback(); } } /*****************************************************************/ /* Subscription methods */ /*****************************************************************/ void KisAslCallbackObjectCatcher::subscribeDouble(const QString &path, ASLCallbackDouble callback) { m_d->mapDouble.insert(path, callback); } void KisAslCallbackObjectCatcher::subscribeInteger(const QString &path, ASLCallbackInteger callback) { m_d->mapInteger.insert(path, callback); } void KisAslCallbackObjectCatcher::subscribeEnum(const QString &path, const QString &typeId, ASLCallbackString callback) { m_d->mapEnum.insert(path, EnumMapping(typeId, callback)); } void KisAslCallbackObjectCatcher::subscribeUnitFloat(const QString &path, const QString &unit, ASLCallbackDouble callback) { m_d->mapUnitFloat.insert(path, UnitFloatMapping(unit, callback)); } void KisAslCallbackObjectCatcher::subscribeText(const QString &path, ASLCallbackString callback) { m_d->mapText.insert(path, callback); } void KisAslCallbackObjectCatcher::subscribeBoolean(const QString &path, ASLCallbackBoolean callback) { m_d->mapBoolean.insert(path, callback); } void KisAslCallbackObjectCatcher::subscribeColor(const QString &path, ASLCallbackColor callback) { m_d->mapColor.insert(path, callback); } void KisAslCallbackObjectCatcher::subscribePoint(const QString &path, ASLCallbackPoint callback) { m_d->mapPoint.insert(path, callback); } void KisAslCallbackObjectCatcher::subscribeCurve(const QString &path, ASLCallbackCurve callback) { m_d->mapCurve.insert(path, callback); } void KisAslCallbackObjectCatcher::subscribePattern(const QString &path, ASLCallbackPattern callback) { m_d->mapPattern.insert(path, callback); } void KisAslCallbackObjectCatcher::subscribePatternRef(const QString &path, ASLCallbackPatternRef callback) { m_d->mapPatternRef.insert(path, callback); } void KisAslCallbackObjectCatcher::subscribeGradient(const QString &path, ASLCallbackGradient callback) { m_d->mapGradient.insert(path, callback); } void KisAslCallbackObjectCatcher::subscribeNewStyleStarted(ASLCallbackNewStyle callback) { m_d->newStyleCallback = callback; } diff --git a/libs/psd/asl/kis_asl_callback_object_catcher.h b/libs/psd/asl/kis_asl_callback_object_catcher.h index 0e9a6f2839..a05079a727 100644 --- a/libs/psd/asl/kis_asl_callback_object_catcher.h +++ b/libs/psd/asl/kis_asl_callback_object_catcher.h @@ -1,85 +1,85 @@ /* * 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. */ #ifndef __KIS_ASL_CALLBACK_OBJECT_CATCHER_H #define __KIS_ASL_CALLBACK_OBJECT_CATCHER_H #include "kis_asl_object_catcher.h" #include #include #include #include "kritapsd_export.h" class KoPattern; typedef boost::function ASLCallbackDouble; typedef boost::function ASLCallbackInteger; typedef boost::function ASLCallbackString; typedef boost::function ASLCallbackBoolean; typedef boost::function ASLCallbackColor; typedef boost::function ASLCallbackPoint; typedef boost::function &)> ASLCallbackCurve; -typedef boost::function ASLCallbackPattern; +typedef boost::function ASLCallbackPattern; typedef boost::function ASLCallbackPatternRef; typedef boost::function ASLCallbackGradient; typedef boost::function ASLCallbackNewStyle; class KRITAPSD_EXPORT KisAslCallbackObjectCatcher : public KisAslObjectCatcher { public: KisAslCallbackObjectCatcher(); ~KisAslCallbackObjectCatcher() override; void addDouble(const QString &path, double value) override; void addInteger(const QString &path, int value) override; void addEnum(const QString &path, const QString &typeId, const QString &value) override; void addUnitFloat(const QString &path, const QString &unit, double value) override; void addText(const QString &path, const QString &value) override; void addBoolean(const QString &path, bool value) override; void addColor(const QString &path, const QColor &value) override; void addPoint(const QString &path, const QPointF &value) override; void addCurve(const QString &path, const QString &name, const QVector &points) override; - void addPattern(const QString &path, const KoPattern *pattern) override; + void addPattern(const QString &path, const KoPatternSP pattern) override; void addPatternRef(const QString &path, const QString &patternUuid, const QString &patternName) override; void addGradient(const QString &path, KoAbstractGradientSP gradient) override; void newStyleStarted() override; void subscribeDouble(const QString &path, ASLCallbackDouble callback); void subscribeInteger(const QString &path, ASLCallbackInteger callback); void subscribeEnum(const QString &path, const QString &typeId, ASLCallbackString callback); void subscribeUnitFloat(const QString &path, const QString &unit, ASLCallbackDouble callback); void subscribeText(const QString &path, ASLCallbackString callback); void subscribeBoolean(const QString &path, ASLCallbackBoolean callback); void subscribeColor(const QString &path, ASLCallbackColor callback); void subscribePoint(const QString &path, ASLCallbackPoint callback); void subscribeCurve(const QString &path, ASLCallbackCurve callback); void subscribePattern(const QString &path, ASLCallbackPattern callback); void subscribePatternRef(const QString &path, ASLCallbackPatternRef callback); void subscribeGradient(const QString &path, ASLCallbackGradient callback); void subscribeNewStyleStarted(ASLCallbackNewStyle callback); private: struct Private; const QScopedPointer m_d; }; #endif /* __KIS_ASL_CALLBACK_OBJECT_CATCHER_H */ diff --git a/libs/psd/asl/kis_asl_object_catcher.cpp b/libs/psd/asl/kis_asl_object_catcher.cpp index d2585f04ff..1271c3e0ab 100644 --- a/libs/psd/asl/kis_asl_object_catcher.cpp +++ b/libs/psd/asl/kis_asl_object_catcher.cpp @@ -1,97 +1,97 @@ /* * 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_object_catcher.h" #include #include #include #include #include KisAslObjectCatcher::KisAslObjectCatcher() : m_arrayMode(false) { } KisAslObjectCatcher::~KisAslObjectCatcher() { } void KisAslObjectCatcher::addDouble(const QString &path, double value) { dbgKrita << "Unhandled:" << (m_arrayMode ? "[A]" : "[ ]") << path << "double" << value; } void KisAslObjectCatcher::addInteger(const QString &path, int value) { dbgKrita << "Unhandled:" << (m_arrayMode ? "[A]" : "[ ]") << path << "int" << value; } void KisAslObjectCatcher::addEnum(const QString &path, const QString &typeId, const QString &value) { dbgKrita << "Unhandled:" << (m_arrayMode ? "[A]" : "[ ]") << path << "enum" << ppVar(typeId) << ppVar(value); } void KisAslObjectCatcher::addUnitFloat(const QString &path, const QString &unit, double value) { dbgKrita << "Unhandled:" << (m_arrayMode ? "[A]" : "[ ]") << path << "unitfloat" << ppVar(unit) << ppVar(value); } void KisAslObjectCatcher::addText(const QString &path, const QString &value) { dbgKrita << "Unhandled:" << (m_arrayMode ? "[A]" : "[ ]") << path << "text" << value; } void KisAslObjectCatcher::addBoolean(const QString &path, bool value) { dbgKrita << "Unhandled:" << (m_arrayMode ? "[A]" : "[ ]") << path << "bool" << value; } void KisAslObjectCatcher::addColor(const QString &path, const QColor &value) { dbgKrita << "Unhandled:" << (m_arrayMode ? "[A]" : "[ ]") << path << "color" << value; } void KisAslObjectCatcher::addPoint(const QString &path, const QPointF &value) { dbgKrita << "Unhandled:" << (m_arrayMode ? "[A]" : "[ ]") << path << "point" << value; } void KisAslObjectCatcher::addCurve(const QString &path, const QString &name, const QVector &points) { dbgKrita << "Unhandled:" << (m_arrayMode ? "[A]" : "[ ]") << path << "curve" << name << ppVar(points.size()); } -void KisAslObjectCatcher::addPattern(const QString &path, const KoPattern *value) +void KisAslObjectCatcher::addPattern(const QString &path, const KoPatternSP value) { dbgKrita << "Unhandled:" << (m_arrayMode ? "[A]" : "[ ]") << path << "pattern" << value; } void KisAslObjectCatcher::addPatternRef(const QString &path, const QString &patternUuid, const QString &patternName) { dbgKrita << "Unhandled:" << (m_arrayMode ? "[A]" : "[ ]") << path << "pattern-ref" << ppVar(patternUuid) << ppVar(patternName); } void KisAslObjectCatcher::addGradient(const QString &path, KoAbstractGradientSP value) { dbgKrita << "Unhandled:" << (m_arrayMode ? "[A]" : "[ ]") << path << "gradient" << value; } void KisAslObjectCatcher::newStyleStarted() { dbgKrita << "Unhandled:" << "new style started"; } void KisAslObjectCatcher::setArrayMode(bool value) { m_arrayMode = value; } diff --git a/libs/psd/asl/kis_asl_object_catcher.h b/libs/psd/asl/kis_asl_object_catcher.h index a674c987d7..bb2e83a8b1 100644 --- a/libs/psd/asl/kis_asl_object_catcher.h +++ b/libs/psd/asl/kis_asl_object_catcher.h @@ -1,60 +1,62 @@ /* * 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. */ #ifndef __KIS_ASL_OBJECT_CATCHER_H #define __KIS_ASL_OBJECT_CATCHER_H #include -#include "kritapsd_export.h" + +#include class QString; class QColor; class QPointF; -class KoPattern; class KoAbstractGradient; +#include "kritapsd_export.h" + template class QSharedPointer; typedef QSharedPointer KoAbstractGradientSP; class KRITAPSD_EXPORT KisAslObjectCatcher { public: KisAslObjectCatcher(); virtual ~KisAslObjectCatcher(); virtual void addDouble(const QString &path, double value); virtual void addInteger(const QString &path, int value); virtual void addEnum(const QString &path, const QString &typeId, const QString &value); virtual void addUnitFloat(const QString &path, const QString &unit, double value); virtual void addText(const QString &path, const QString &value); virtual void addBoolean(const QString &path, bool value); virtual void addColor(const QString &path, const QColor &value); virtual void addPoint(const QString &path, const QPointF &value); virtual void addCurve(const QString &path, const QString &name, const QVector &points); - virtual void addPattern(const QString &path, const KoPattern *pattern); + virtual void addPattern(const QString &path, const KoPatternSP pattern); virtual void addPatternRef(const QString &path, const QString &patternUuid, const QString &patternName); virtual void addGradient(const QString &path, KoAbstractGradientSP gradient); virtual void newStyleStarted(); void setArrayMode(bool value); protected: bool m_arrayMode; }; #endif /* __KIS_ASL_OBJECT_CATCHER_H */ diff --git a/libs/psd/asl/kis_asl_patterns_writer.cpp b/libs/psd/asl/kis_asl_patterns_writer.cpp index 4c9a0f8c8a..ac1f5814a2 100644 --- a/libs/psd/asl/kis_asl_patterns_writer.cpp +++ b/libs/psd/asl/kis_asl_patterns_writer.cpp @@ -1,206 +1,206 @@ /* * 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_patterns_writer.h" #include #include #include "kis_asl_callback_object_catcher.h" #include "kis_asl_xml_parser.h" #include "kis_debug.h" #include "compression.h" #include "kis_asl_writer_utils.h" KisAslPatternsWriter::KisAslPatternsWriter(const QDomDocument &doc, QIODevice *device) : m_doc(doc), m_device(device), m_numPatternsWritten(0) { } void KisAslPatternsWriter::writePatterns() { KisAslCallbackObjectCatcher c; c.subscribePattern("/Patterns/KisPattern", std::bind(&KisAslPatternsWriter::addPattern, this, std::placeholders::_1)); KisAslXmlParser parser; parser.parseXML(m_doc, c); } void sliceQImage(const QImage &image, QVector > *dstPlanes, bool *isCompressed) { KIS_ASSERT_RECOVER_NOOP(image.format() == QImage::Format_ARGB32); QVector > uncompressedRows; QVector > compressedRows; uncompressedRows.resize(3); compressedRows.resize(3); int compressedSize = 0; for (int i = 0; i < 3; i++) { const int srcRowOffset = 2 - i; const int srcStep = 4; const int dstStep = 1; for (int row = 0; row < image.height(); row++) { uncompressedRows[i].append(QByteArray(image.width(), '\0')); quint8 *dstPtr = (quint8*)uncompressedRows[i].last().data(); const quint8 *srcPtr = image.constScanLine(row) + srcRowOffset; for (int col = 0; col < image.width(); col++) { *dstPtr = *srcPtr; srcPtr += srcStep; dstPtr += dstStep; } compressedRows[i].append(Compression::compress(uncompressedRows[i].last(), Compression::RLE)); if (compressedRows[i].last().isEmpty()) { throw KisAslWriterUtils::ASLWriteException("Failed to compress pattern plane"); } compressedSize += compressedRows[i].last().size() + 2; // two bytes for offset tag } } if (compressedSize < image.width() * image.height() * 3) { *dstPlanes = compressedRows; *isCompressed = true; } else { *dstPlanes = uncompressedRows; *isCompressed = false; } } -void KisAslPatternsWriter::addPattern(const KoPattern *pattern) +void KisAslPatternsWriter::addPattern(const KoPatternSP pattern) { { KisAslWriterUtils::OffsetStreamPusher patternSizeField(m_device); { const quint32 patternVersion = 1; SAFE_WRITE_EX(m_device, patternVersion); } { const quint32 patternImageMode = 3; SAFE_WRITE_EX(m_device, patternImageMode); } { const quint16 patternHeight = pattern->height(); SAFE_WRITE_EX(m_device, patternHeight); } { const quint16 patternWidth = pattern->width(); SAFE_WRITE_EX(m_device, patternWidth); } KisAslWriterUtils::writeUnicodeString(pattern->name(), m_device); KisAslWriterUtils::writePascalString(KisAslWriterUtils::getPatternUuidLazy(pattern), m_device); // Write "Virtual Memory Array List" const QRect patternRect(0, 0, pattern->width(), pattern->height()); { { const quint32 arrayVersion = 3; SAFE_WRITE_EX(m_device, arrayVersion); } KisAslWriterUtils::OffsetStreamPusher arraySizeField(m_device); KisAslWriterUtils::writeRect(patternRect, m_device); { // don't ask me why it is called this way... const quint32 numberOfChannels = 24; SAFE_WRITE_EX(m_device, numberOfChannels); } KIS_ASSERT_RECOVER_RETURN(patternRect.size() == pattern->pattern().size()); QVector > imagePlanes; bool isCompressed; sliceQImage(pattern->pattern(), &imagePlanes, &isCompressed); for (int i = 0; i < 3; i++) { { const quint32 planeIsWritten = 1; SAFE_WRITE_EX(m_device, planeIsWritten); } KisAslWriterUtils::OffsetStreamPusher planeSizeField(m_device); { const quint32 pixelDepth1 = 8; SAFE_WRITE_EX(m_device, pixelDepth1); } KisAslWriterUtils::writeRect(patternRect, m_device); { // why twice? who knows... const quint16 pixelDepth2 = 8; SAFE_WRITE_EX(m_device, pixelDepth2); } { // compress with RLE const quint8 compressionMethod = isCompressed; SAFE_WRITE_EX(m_device, compressionMethod); } KIS_ASSERT_RECOVER_RETURN(imagePlanes[i].size() == pattern->pattern().height()); if (isCompressed) { Q_FOREACH (const QByteArray &compressedRow, imagePlanes[i]) { const quint16 compressionRowSize = compressedRow.size(); SAFE_WRITE_EX(m_device, compressionRowSize); } } Q_FOREACH (const QByteArray &rowData, imagePlanes[i]) { int bytesWritten = m_device->write(rowData); if (bytesWritten != rowData.size()) { throw KisAslWriterUtils::ASLWriteException("Failed to write a compressed pattern plane"); } } } } } const qint64 currentPos = m_device->pos(); const qint64 alignedPos = KisAslWriterUtils::alignOffsetCeil(currentPos, 4); if (currentPos != alignedPos) { m_device->seek(alignedPos); } m_numPatternsWritten++; } diff --git a/libs/psd/asl/kis_asl_patterns_writer.h b/libs/psd/asl/kis_asl_patterns_writer.h index ddeda08293..de7b7e3010 100644 --- a/libs/psd/asl/kis_asl_patterns_writer.h +++ b/libs/psd/asl/kis_asl_patterns_writer.h @@ -1,47 +1,46 @@ /* * 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. */ #ifndef __KIS_ASL_PATTERNS_WRITER_H #define __KIS_ASL_PATTERNS_WRITER_H #include "kritapsd_export.h" class QDomDocument; class QIODevice; -class KoPattern; - +#include class KRITAPSD_EXPORT KisAslPatternsWriter { public: KisAslPatternsWriter(const QDomDocument &doc, QIODevice *device); void writePatterns(); private: - void addPattern(const KoPattern *pattern); + void addPattern(const KoPatternSP pattern); private: const QDomDocument &m_doc; QIODevice *m_device; int m_numPatternsWritten; }; #endif /* __KIS_ASL_PATTERNS_WRITER_H */ diff --git a/libs/psd/asl/kis_asl_writer_utils.cpp b/libs/psd/asl/kis_asl_writer_utils.cpp index 806314586f..82e99f861c 100644 --- a/libs/psd/asl/kis_asl_writer_utils.cpp +++ b/libs/psd/asl/kis_asl_writer_utils.cpp @@ -1,111 +1,111 @@ /* * 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_writer_utils.h" #include #include namespace KisAslWriterUtils { void writeRect(const QRect &rect, QIODevice *device) { { const quint32 rectY0 = rect.y(); SAFE_WRITE_EX(device, rectY0); } { const quint32 rectX0 = rect.x(); SAFE_WRITE_EX(device, rectX0); } { const quint32 rectY1 = rect.y() + rect.height(); SAFE_WRITE_EX(device, rectY1); } { const quint32 rectX1 = rect.x() + rect.width(); SAFE_WRITE_EX(device, rectX1); } } void writeUnicodeString(const QString &value, QIODevice *device) { quint32 len = value.length() + 1; SAFE_WRITE_EX(device, len); const quint16 *ptr = value.utf16(); for (quint32 i = 0; i < len; i++) { SAFE_WRITE_EX(device, ptr[i]); } } void writeVarString(const QString &value, QIODevice *device) { quint32 lenTag = value.length() != 4 ? value.length() : 0; SAFE_WRITE_EX(device, lenTag); if (!device->write(value.toLatin1().data(), value.length())) { warnKrita << "WARNING: ASL: Failed to write ASL string" << ppVar(value); return; } } void writePascalString(const QString &value, QIODevice *device) { quint8 lenTag = value.length(); SAFE_WRITE_EX(device, lenTag); if (!device->write(value.toLatin1().data(), value.length())) { warnKrita << "WARNING: ASL: Failed to write ASL string" << ppVar(value); return; } } void writeFixedString(const QString &value, QIODevice *device) { KIS_ASSERT_RECOVER_RETURN(value.length() == 4); if (!device->write(value.toLatin1().data(), value.length())) { warnKrita << "WARNING: ASL: Failed to write ASL string" << ppVar(value); return; } } // Write UUID fetched from the file name or generate -QString getPatternUuidLazy(const KoPattern *pattern) +QString getPatternUuidLazy(const KoPatternSP pattern) { QUuid uuid; QString patternFileName = pattern->filename(); if (patternFileName.endsWith(".pat", Qt::CaseInsensitive)) { QString strUuid = patternFileName.left(patternFileName.size() - 4); uuid = QUuid(strUuid); } if (uuid.isNull()) { warnKrita << "WARNING: Saved pattern doesn't have a UUID, generating..."; warnKrita << ppVar(patternFileName) << ppVar(pattern->name()); uuid = QUuid::createUuid(); } return uuid.toString().mid(1, 36); } } diff --git a/libs/psd/asl/kis_asl_writer_utils.h b/libs/psd/asl/kis_asl_writer_utils.h index bd1c68dab7..2a975ee3f8 100644 --- a/libs/psd/asl/kis_asl_writer_utils.h +++ b/libs/psd/asl/kis_asl_writer_utils.h @@ -1,137 +1,137 @@ /* * 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. */ #ifndef __KIS_ASL_WRITER_UTILS_H #define __KIS_ASL_WRITER_UTILS_H #include #include #include #include "psd_utils.h" #include "kis_debug.h" #include "kritapsd_export.h" namespace KisAslWriterUtils { /** * Exception that is emitted when any write error appear. */ struct KRITAPSD_EXPORT ASLWriteException : public std::runtime_error { ASLWriteException(const QString &msg) : std::runtime_error(msg.toLatin1().data()) { } }; } #define SAFE_WRITE_EX(device, varname) \ if (!psdwrite(device, varname)) { \ QString msg = QString("Failed to write \'%1\' tag!").arg(#varname); \ throw KisAslWriterUtils::ASLWriteException(msg); \ } namespace KisAslWriterUtils { KRITAPSD_EXPORT void writeRect(const QRect &rect, QIODevice *device); KRITAPSD_EXPORT void writeUnicodeString(const QString &value, QIODevice *device); KRITAPSD_EXPORT void writeVarString(const QString &value, QIODevice *device); KRITAPSD_EXPORT void writePascalString(const QString &value, QIODevice *device); KRITAPSD_EXPORT void writeFixedString(const QString &value, QIODevice *device); -KRITAPSD_EXPORT QString getPatternUuidLazy(const KoPattern *pattern); +KRITAPSD_EXPORT QString getPatternUuidLazy(const KoPatternSP pattern); /** * Align the pointer \p pos by alignment. Grow the pointer * if needed. * * \return the lowest integer not smaller than \p pos that divides by * alignment */ inline qint64 alignOffsetCeil(qint64 pos, qint64 alignment) { qint64 mask = alignment - 1; return (pos + mask) & ~mask; } template class OffsetStreamPusher { public: OffsetStreamPusher(QIODevice *device, qint64 alignOnExit = 0, qint64 externalSizeTagOffset = -1) : m_device(device), m_alignOnExit(alignOnExit), m_externalSizeTagOffset(externalSizeTagOffset) { m_chunkStartPos = m_device->pos(); if (externalSizeTagOffset < 0) { const OffsetType fakeObjectSize = OffsetType(0xdeadbeef); SAFE_WRITE_EX(m_device, fakeObjectSize); } } ~OffsetStreamPusher() { try { if (m_alignOnExit) { qint64 currentPos = m_device->pos(); const qint64 alignedPos = alignOffsetCeil(currentPos, m_alignOnExit); for (; currentPos < alignedPos; currentPos++) { quint8 padding = 0; SAFE_WRITE_EX(m_device, padding); } } const qint64 currentPos = m_device->pos(); qint64 writtenDataSize = 0; qint64 sizeFiledOffset = 0; if (m_externalSizeTagOffset >= 0) { writtenDataSize = currentPos - m_chunkStartPos; sizeFiledOffset = m_externalSizeTagOffset; } else { writtenDataSize = currentPos - m_chunkStartPos - sizeof(OffsetType); sizeFiledOffset = m_chunkStartPos; } m_device->seek(sizeFiledOffset); const OffsetType realObjectSize = writtenDataSize; SAFE_WRITE_EX(m_device, realObjectSize); m_device->seek(currentPos); } catch(ASLWriteException &e) { warnKrita << PREPEND_METHOD(e.what()); } } private: qint64 m_chunkStartPos; QIODevice *m_device; qint64 m_alignOnExit; qint64 m_externalSizeTagOffset; }; } #endif /* __KIS_ASL_WRITER_UTILS_H */ diff --git a/libs/psd/asl/kis_asl_xml_parser.cpp b/libs/psd/asl/kis_asl_xml_parser.cpp index 9b208b3672..dbfd38228d 100644 --- a/libs/psd/asl/kis_asl_xml_parser.cpp +++ b/libs/psd/asl/kis_asl_xml_parser.cpp @@ -1,556 +1,556 @@ /* * 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_parser.h" #include #include #include #include #include #include #include #include #include #include #include "kis_dom_utils.h" #include "kis_debug.h" #include "psd_utils.h" #include "psd.h" #include "compression.h" #include "kis_asl_object_catcher.h" namespace Private { void parseElement(const QDomElement &el, const QString &parentPath, KisAslObjectCatcher &catcher); class CurveObjectCatcher : public KisAslObjectCatcher { public: void addText(const QString &path, const QString &value) override { if (path == "/Nm ") { m_name = value; } else { warnKrita << "XML (ASL): failed to parse curve object" << path << value; } } void addPoint(const QString &path, const QPointF &value) override { if (!m_arrayMode) { warnKrita << "XML (ASL): failed to parse curve object (array fault)" << path << value << ppVar(m_arrayMode); } m_points.append(value); } public: QVector m_points; QString m_name; }; QColor parseRGBColorObject(QDomElement parent) { QColor color(Qt::black); QDomNode child = parent.firstChild(); while (!child.isNull()) { QDomElement childEl = child.toElement(); QString type = childEl.attribute("type", ""); QString key = childEl.attribute("key", ""); if (type != "Double") { warnKrita << "Unknown color component type:" << ppVar(type) << ppVar(key); return Qt::red; } double value = KisDomUtils::toDouble(childEl.attribute("value", "0")); if (key == "Rd ") { color.setRed(value); } else if (key == "Grn ") { color.setGreen(value); } else if (key == "Bl ") { color.setBlue(value); } else { warnKrita << "Unknown color key value:" << ppVar(key); return Qt::red; } child = child.nextSibling(); } return color; } void parseColorStopsList(QDomElement parent, QVector &startLocations, QVector &middleOffsets, QVector &colors) { QDomNode child = parent.firstChild(); while (!child.isNull()) { QDomElement childEl = child.toElement(); QString type = childEl.attribute("type", ""); QString key = childEl.attribute("key", ""); QString classId = childEl.attribute("classId", ""); if (type == "Descriptor" && classId == "Clrt") { // sorry for naming... QDomNode child = childEl.firstChild(); while (!child.isNull()) { QDomElement childEl = child.toElement(); QString type = childEl.attribute("type", ""); QString key = childEl.attribute("key", ""); QString classId = childEl.attribute("classId", ""); if (type == "Integer" && key == "Lctn") { int value = KisDomUtils::toInt(childEl.attribute("value", "0")); startLocations.append(qreal(value) / 4096.0); } else if (type == "Integer" && key == "Mdpn") { int value = KisDomUtils::toInt(childEl.attribute("value", "0")); middleOffsets.append(qreal(value) / 100.0); } else if (type == "Descriptor" && key == "Clr ") { colors.append(parseRGBColorObject(childEl)); } else if (type == "Enum" && key == "Type") { QString typeId = childEl.attribute("typeId", ""); if (typeId != "Clry") { warnKrita << "WARNING: Invalid typeId of a gradient stop type" << typeId; } QString value = childEl.attribute("value", ""); if (value == "BckC" || value == "FrgC") { warnKrita << "WARNING: Using foreground/background colors in ASL gradients is not yet supported"; } } child = child.nextSibling(); } } else { warnKrita << "WARNING: Unrecognized object in color stops list" << ppVar(type) << ppVar(key) << ppVar(classId); } child = child.nextSibling(); } } void parseTransparencyStopsList(QDomElement parent, QVector &startLocations, QVector &middleOffsets, QVector &transparencies) { QDomNode child = parent.firstChild(); while (!child.isNull()) { QDomElement childEl = child.toElement(); QString type = childEl.attribute("type", ""); QString key = childEl.attribute("key", ""); QString classId = childEl.attribute("classId", ""); if (type == "Descriptor" && classId == "TrnS") { // sorry for naming again... QDomNode child = childEl.firstChild(); while (!child.isNull()) { QDomElement childEl = child.toElement(); QString type = childEl.attribute("type", ""); QString key = childEl.attribute("key", ""); if (type == "Integer" && key == "Lctn") { int value = KisDomUtils::toInt(childEl.attribute("value", "0")); startLocations.append(qreal(value) / 4096.0); } else if (type == "Integer" && key == "Mdpn") { int value = KisDomUtils::toInt(childEl.attribute("value", "0")); middleOffsets.append(qreal(value) / 100.0); } else if (type == "UnitFloat" && key == "Opct") { QString unit = childEl.attribute("unit", ""); if (unit != "#Prc") { warnKrita << "WARNING: Invalid unit of a gradient stop transparency" << unit; } qreal value = KisDomUtils::toDouble(childEl.attribute("value", "100")); transparencies.append(value / 100.0); } child = child.nextSibling(); } } else { warnKrita << "WARNING: Unrecognized object in transparency stops list" << ppVar(type) << ppVar(key) << ppVar(classId); } child = child.nextSibling(); } } inline QString buildPath(const QString &parent, const QString &key) { return parent + "/" + key; } bool tryParseDescriptor(const QDomElement &el, const QString &path, const QString &classId, KisAslObjectCatcher &catcher) { bool retval = true; if (classId == "null") { catcher.newStyleStarted(); // here we just notify that a new style is started, we haven't // processed the whole block yet, so return false. retval = false; } else if (classId == "RGBC") { catcher.addColor(path, parseRGBColorObject(el)); } else if (classId == "ShpC") { CurveObjectCatcher curveCatcher; QDomNode child = el.firstChild(); while (!child.isNull()) { parseElement(child.toElement(), "", curveCatcher); child = child.nextSibling(); } catcher.addCurve(path, curveCatcher.m_name, curveCatcher.m_points); } else if (classId == "CrPt") { QPointF point; QDomNode child = el.firstChild(); while (!child.isNull()) { QDomElement childEl = child.toElement(); QString type = childEl.attribute("type", ""); QString key = childEl.attribute("key", ""); if (type == "Boolean" && key == "Cnty") { warnKrita << "WARNING: tryParseDescriptor: The points of the curve object contain \'Cnty\' flag which is unsupported by Krita"; warnKrita << " " << ppVar(type) << ppVar(key) << ppVar(path); child = child.nextSibling(); continue; } if (type != "Double") { warnKrita << "Unknown point component type:" << ppVar(type) << ppVar(key) << ppVar(path); return false; } double value = KisDomUtils::toDouble(childEl.attribute("value", "0")); if (key == "Hrzn") { point.setX(value); } else if (key == "Vrtc") { point.setY(value); } else { warnKrita << "Unknown point key value:" << ppVar(key) << ppVar(path); return false; } child = child.nextSibling(); } catcher.addPoint(path, point); } else if (classId == "Pnt ") { QPointF point; QDomNode child = el.firstChild(); while (!child.isNull()) { QDomElement childEl = child.toElement(); QString type = childEl.attribute("type", ""); QString key = childEl.attribute("key", ""); QString unit = childEl.attribute("unit", ""); if (type != "Double" && !(type == "UnitFloat" && unit == "#Prc")) { warnKrita << "Unknown point component type:" << ppVar(unit) << ppVar(type) << ppVar(key) << ppVar(path); return false; } double value = KisDomUtils::toDouble(childEl.attribute("value", "0")); if (key == "Hrzn") { point.setX(value); } else if (key == "Vrtc") { point.setY(value); } else { warnKrita << "Unknown point key value:" << ppVar(key) << ppVar(path); return false; } child = child.nextSibling(); } catcher.addPoint(path, point); } else if (classId == "KisPattern") { QByteArray patternData; QString patternUuid; QDomNode child = el.firstChild(); while (!child.isNull()) { QDomElement childEl = child.toElement(); QString type = childEl.attribute("type", ""); QString key = childEl.attribute("key", ""); if (type == "Text" && key == "Idnt") { patternUuid = childEl.attribute("value", ""); } if (type == "KisPatternData" && key == "Data") { QDomNode dataNode = child.firstChild(); if (!dataNode.isCDATASection()) { warnKrita << "WARNING: failed to parse KisPatternData XML section!"; continue; } QDomCDATASection dataSection = dataNode.toCDATASection(); QByteArray data = dataSection.data().toLatin1(); data = QByteArray::fromBase64(data); data = qUncompress(data); if (data.isEmpty()) { warnKrita << "WARNING: failed to parse KisPatternData XML section!"; continue; } patternData = data; } child = child.nextSibling(); } if (!patternUuid.isEmpty() && !patternData.isEmpty()) { QString fileName = QString("%1.pat").arg(patternUuid); - QScopedPointer pattern(new KoPattern(fileName)); + QSharedPointer pattern(new KoPattern(fileName)); QBuffer buffer(&patternData); buffer.open(QIODevice::ReadOnly); pattern->loadPatFromDevice(&buffer); - catcher.addPattern(path, pattern.data()); + catcher.addPattern(path, pattern); } else { warnKrita << "WARNING: failed to load KisPattern XML section!" << ppVar(patternUuid); } } else if (classId == "Ptrn") { // reference to an existing pattern QString patternUuid; QString patternName; QDomNode child = el.firstChild(); while (!child.isNull()) { QDomElement childEl = child.toElement(); QString type = childEl.attribute("type", ""); QString key = childEl.attribute("key", ""); if (type == "Text" && key == "Idnt") { patternUuid = childEl.attribute("value", ""); } else if (type == "Text" && key == "Nm ") { patternName = childEl.attribute("value", ""); } else { warnKrita << "WARNING: unrecognized pattern-ref section key:" << ppVar(type) << ppVar(key); } child = child.nextSibling(); } catcher.addPatternRef(path, patternUuid, patternName); } else if (classId == "Grdn") { QString gradientName; qreal gradientSmoothness = 100.0; QVector startLocations; QVector middleOffsets; QVector colors; QVector transpStartLocations; QVector transpMiddleOffsets; QVector transparencies; QDomNode child = el.firstChild(); while (!child.isNull()) { QDomElement childEl = child.toElement(); QString type = childEl.attribute("type", ""); QString key = childEl.attribute("key", ""); if (type == "Text" && key == "Nm ") { gradientName = childEl.attribute("value", ""); } else if (type == "Enum" && key == "GrdF") { QString typeId = childEl.attribute("typeId", ""); QString value = childEl.attribute("value", ""); if (typeId != "GrdF" || value != "CstS") { warnKrita << "WARNING: Unsupported gradient type (porbably, noise-based):" << value; return true; } } else if (type == "Double" && key == "Intr") { double value = KisDomUtils::toDouble(childEl.attribute("value", "4096")); gradientSmoothness = 100.0 * value / 4096.0; } else if (type == "List" && key == "Clrs") { parseColorStopsList(childEl, startLocations, middleOffsets, colors); } else if (type == "List" && key == "Trns") { parseTransparencyStopsList(childEl, transpStartLocations, transpMiddleOffsets, transparencies); } child = child.nextSibling(); } if (colors.size() < 2) { warnKrita << "WARNING: ASL gradient has too few stops" << ppVar(colors.size()); } if (colors.size() != transparencies.size()) { warnKrita << "WARNING: ASL gradient has inconsistent number of transparency stops. Dropping transparency..." << ppVar(colors.size()) << ppVar(transparencies.size()); transparencies.resize(colors.size()); for (int i = 0; i < colors.size(); i++) { transparencies[i] = 1.0; } } QString fileName = gradientName + ".ggr"; QSharedPointer gradient(new KoSegmentGradient(fileName)); Q_UNUSED(gradientSmoothness); gradient->setName(gradientName); for (int i = 1; i < colors.size(); i++) { QColor startColor = colors[i-1]; QColor endColor = colors[i]; startColor.setAlphaF(transparencies[i-1]); endColor.setAlphaF(transparencies[i]); qreal start = startLocations[i-1]; qreal end = startLocations[i]; qreal middle = start + middleOffsets[i-1] * (end - start); gradient->createSegment(INTERP_LINEAR, COLOR_INTERP_RGB, start, end, middle, startColor, endColor); } gradient->setValid(true); catcher.addGradient(path, gradient); } else { retval = false; } return retval; } void parseElement(const QDomElement &el, const QString &parentPath, KisAslObjectCatcher &catcher) { KIS_ASSERT_RECOVER_RETURN(el.tagName() == "node"); QString type = el.attribute("type", ""); QString key = el.attribute("key", ""); if (type == "Descriptor") { QString classId = el.attribute("classId", ""); QString containerName = key.isEmpty() ? classId : key; QString containerPath = buildPath(parentPath, containerName); if (!tryParseDescriptor(el, containerPath, classId, catcher)) { QDomNode child = el.firstChild(); while (!child.isNull()) { parseElement(child.toElement(), containerPath, catcher); child = child.nextSibling(); } } } else if (type == "List") { catcher.setArrayMode(true); QString containerName = key; QString containerPath = buildPath(parentPath, containerName); QDomNode child = el.firstChild(); while (!child.isNull()) { parseElement(child.toElement(), containerPath, catcher); child = child.nextSibling(); } catcher.setArrayMode(false); } else if (type == "Double") { double v = KisDomUtils::toDouble(el.attribute("value", "0")); catcher.addDouble(buildPath(parentPath, key), v); } else if (type == "UnitFloat") { QString unit = el.attribute("unit", ""); double v = KisDomUtils::toDouble(el.attribute("value", "0")); catcher.addUnitFloat(buildPath(parentPath, key), unit, v); } else if (type == "Text") { QString v = el.attribute("value", ""); catcher.addText(buildPath(parentPath, key), v); } else if (type == "Enum") { QString v = el.attribute("value", ""); QString typeId = el.attribute("typeId", ""); catcher.addEnum(buildPath(parentPath, key), typeId, v); } else if (type == "Integer") { int v = KisDomUtils::toInt(el.attribute("value", "0")); catcher.addInteger(buildPath(parentPath, key), v); } else if (type == "Boolean") { int v = KisDomUtils::toInt(el.attribute("value", "0")); catcher.addBoolean(buildPath(parentPath, key), v); } else { warnKrita << "WARNING: XML (ASL) Unknown element type:" << type << ppVar(parentPath) << ppVar(key); } } } // namespace void KisAslXmlParser::parseXML(const QDomDocument &doc, KisAslObjectCatcher &catcher) { QDomElement root = doc.documentElement(); if (root.tagName() != "asl") { return; } QDomNode child = root.firstChild(); while (!child.isNull()) { Private::parseElement(child.toElement(), "", catcher); child = child.nextSibling(); } } diff --git a/libs/psd/asl/kis_asl_xml_writer.cpp b/libs/psd/asl/kis_asl_xml_writer.cpp index 3250119321..e147061ad1 100644 --- a/libs/psd/asl/kis_asl_xml_writer.cpp +++ b/libs/psd/asl/kis_asl_xml_writer.cpp @@ -1,397 +1,397 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_asl_xml_writer.h" #include #include #include #include #include #include #include #include #include #include "kis_dom_utils.h" #include "kis_asl_writer_utils.h" struct KisAslXmlWriter::Private { QDomDocument document; QDomElement currentElement; }; KisAslXmlWriter::KisAslXmlWriter() : m_d(new Private) { QDomElement el = m_d->document.createElement("asl"); m_d->document.appendChild(el); m_d->currentElement = el; } KisAslXmlWriter::~KisAslXmlWriter() { } QDomDocument KisAslXmlWriter::document() const { if (m_d->document.documentElement() != m_d->currentElement) { warnKrita << "KisAslXmlWriter::document(): unbalanced enter/leave descriptor/array"; } return m_d->document; } void KisAslXmlWriter::enterDescriptor(const QString &key, const QString &name, const QString &classId) { QDomElement el = m_d->document.createElement("node"); if (!key.isEmpty()) { el.setAttribute("key", key); } el.setAttribute("type", "Descriptor"); el.setAttribute("name", name); el.setAttribute("classId", classId); m_d->currentElement.appendChild(el); m_d->currentElement = el; } void KisAslXmlWriter::leaveDescriptor() { if (!m_d->currentElement.parentNode().toElement().isNull()) { m_d->currentElement = m_d->currentElement.parentNode().toElement(); } else { warnKrita << "KisAslXmlWriter::leaveDescriptor(): unbalanced enter/leave descriptor"; } } void KisAslXmlWriter::enterList(const QString &key) { QDomElement el = m_d->document.createElement("node"); if (!key.isEmpty()) { el.setAttribute("key", key); } el.setAttribute("type", "List"); m_d->currentElement.appendChild(el); m_d->currentElement = el; } void KisAslXmlWriter::leaveList() { if (!m_d->currentElement.parentNode().toElement().isNull()) { m_d->currentElement = m_d->currentElement.parentNode().toElement(); } else { warnKrita << "KisAslXmlWriter::leaveList(): unbalanced enter/leave list"; } } void KisAslXmlWriter::writeDouble(const QString &key, double value) { QDomElement el = m_d->document.createElement("node"); if (!key.isEmpty()) { el.setAttribute("key", key); } el.setAttribute("type", "Double"); el.setAttribute("value", KisDomUtils::toString(value)); m_d->currentElement.appendChild(el); } void KisAslXmlWriter::writeInteger(const QString &key, int value) { QDomElement el = m_d->document.createElement("node"); if (!key.isEmpty()) { el.setAttribute("key", key); } el.setAttribute("type", "Integer"); el.setAttribute("value", KisDomUtils::toString(value)); m_d->currentElement.appendChild(el); } void KisAslXmlWriter::writeEnum(const QString &key, const QString &typeId, const QString &value) { QDomElement el = m_d->document.createElement("node"); if (!key.isEmpty()) { el.setAttribute("key", key); } el.setAttribute("type", "Enum"); el.setAttribute("typeId", typeId); el.setAttribute("value", value); m_d->currentElement.appendChild(el); } void KisAslXmlWriter::writeUnitFloat(const QString &key, const QString &unit, double value) { QDomElement el = m_d->document.createElement("node"); if (!key.isEmpty()) { el.setAttribute("key", key); } el.setAttribute("type", "UnitFloat"); el.setAttribute("unit", unit); el.setAttribute("value", KisDomUtils::toString(value)); m_d->currentElement.appendChild(el); } void KisAslXmlWriter::writeText(const QString &key, const QString &value) { QDomElement el = m_d->document.createElement("node"); if (!key.isEmpty()) { el.setAttribute("key", key); } el.setAttribute("type", "Text"); el.setAttribute("value", value); m_d->currentElement.appendChild(el); } void KisAslXmlWriter::writeBoolean(const QString &key, bool value) { QDomElement el = m_d->document.createElement("node"); if (!key.isEmpty()) { el.setAttribute("key", key); } el.setAttribute("type", "Boolean"); el.setAttribute("value", KisDomUtils::toString(value)); m_d->currentElement.appendChild(el); } void KisAslXmlWriter::writeColor(const QString &key, const QColor &value) { enterDescriptor(key, "", "RGBC"); writeDouble("Rd ", value.red()); writeDouble("Grn ", value.green()); writeDouble("Bl ", value.blue()); leaveDescriptor(); } void KisAslXmlWriter::writePoint(const QString &key, const QPointF &value) { enterDescriptor(key, "", "CrPt"); writeDouble("Hrzn", value.x()); writeDouble("Vrtc", value.y()); leaveDescriptor(); } void KisAslXmlWriter::writePhasePoint(const QString &key, const QPointF &value) { enterDescriptor(key, "", "Pnt "); writeDouble("Hrzn", value.x()); writeDouble("Vrtc", value.y()); leaveDescriptor(); } void KisAslXmlWriter::writeOffsetPoint(const QString &key, const QPointF &value) { enterDescriptor(key, "", "Pnt "); writeUnitFloat("Hrzn", "#Prc", value.x()); writeUnitFloat("Vrtc", "#Prc", value.y()); leaveDescriptor(); } void KisAslXmlWriter::writeCurve(const QString &key, const QString &name, const QVector &points) { enterDescriptor(key, "", "ShpC"); writeText("Nm ", name); enterList("Crv "); Q_FOREACH (const QPointF &pt, points) { writePoint("", pt); } leaveList(); leaveDescriptor(); } -QString KisAslXmlWriter::writePattern(const QString &key, const KoPattern *pattern) +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 KoPattern *pattern, const QString &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(); 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 { const KoGradientSegment *lastSeg = segments.last(); QColor color = lastSeg->endColor().toQColor(); qreal transparency = color.alphaF(); color.setAlphaF(1.0); colors << color; transparencies << transparency; positions << lastSeg->endOffset(); middleOffsets << 0.5; } writeGradientImpl(key, gradient->name(), colors, transparencies, positions, middleOffsets); } void KisAslXmlWriter::writeStopGradient(const QString &key, const KoStopGradient *gradient) { QVector colors; QVector transparencies; QVector positions; QVector middleOffsets; Q_FOREACH (const KoGradientStop &stop, gradient->stops()) { QColor color = stop.second.toQColor(); qreal transparency = color.alphaF(); color.setAlphaF(1.0); colors << color; transparencies << transparency; positions << stop.first; middleOffsets << 0.5; } writeGradientImpl(key, gradient->name(), colors, transparencies, positions, middleOffsets); } diff --git a/libs/psd/asl/kis_asl_xml_writer.h b/libs/psd/asl/kis_asl_xml_writer.h index 46b8746d06..aaf11be2f8 100644 --- a/libs/psd/asl/kis_asl_xml_writer.h +++ b/libs/psd/asl/kis_asl_xml_writer.h @@ -1,79 +1,81 @@ /* * 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. */ #ifndef __KIS_ASL_XML_WRITER_H #define __KIS_ASL_XML_WRITER_H #include #include +#include + #include "kritapsd_export.h" class QString; class QColor; class QPointF; class QDomDocument; -class KoPattern; + class KoStopGradient; class KoSegmentGradient; class KRITAPSD_EXPORT KisAslXmlWriter { public: KisAslXmlWriter(); ~KisAslXmlWriter(); QDomDocument document() const; void enterDescriptor(const QString &key, const QString &name, const QString &classId); void leaveDescriptor(); void enterList(const QString &key); void leaveList(); void writeDouble(const QString &key, double value); void writeInteger(const QString &key, int value); void writeEnum(const QString &key, const QString &typeId, const QString &value); void writeUnitFloat(const QString &key, const QString &unit, double value); void writeText(const QString &key, const QString &value); void writeBoolean(const QString &key, bool value); void writeColor(const QString &key, const QColor &value); void writePoint(const QString &key, const QPointF &value); void writePhasePoint(const QString &key, const QPointF &value); void writeOffsetPoint(const QString &key, const QPointF &value); void writeCurve(const QString &key, const QString &name, const QVector &points); - QString writePattern(const QString &key, const KoPattern *pattern); - void writePatternRef(const QString &key, const KoPattern *pattern, const QString &uuid); + QString writePattern(const QString &key, const KoPatternSP pattern); + void writePatternRef(const QString &key, const KoPatternSP pattern, const QString &uuid); void writeSegmentGradient(const QString &key, const KoSegmentGradient *gradient); void writeStopGradient(const QString &key, const KoStopGradient *gradient); private: void writeGradientImpl(const QString &key, const QString &name, QVector colors, QVector transparencies, QVector positions, QVector middleOffsets); private: struct Private; const QScopedPointer m_d; }; #endif /* __KIS_ASL_XML_WRITER_H */ diff --git a/libs/psd/psd.h b/libs/psd/psd.h index de131447f8..7afd9172e5 100644 --- a/libs/psd/psd.h +++ b/libs/psd/psd.h @@ -1,1168 +1,1168 @@ /* * Copyright (c) 2010 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. */ /* * Constants and defines taken from gimp and psdparse */ #ifndef PSD_H #define PSD_H #include #include #include #include #include #include #include - +#include #include "kritapsd_export.h" -class KoPattern; + const int MAX_CHANNELS = 56; typedef qint32 Fixed; /* Represents a fixed point implied decimal */ /** * Image color/depth modes */ enum psd_color_mode { Bitmap = 0, Grayscale=1, Indexed=2, RGB=3, CMYK=4, MultiChannel=7, DuoTone=8, Lab=9, Gray16, RGB48, Lab48, CMYK64, DeepMultichannel, Duotone16, COLORMODE_UNKNOWN = 9000 }; /** * Color samplers, apparently distict from PSDColormode */ namespace psd_color_sampler { enum PSDColorSamplers { RGB, HSB, CMYK, PANTONE, // LAB FOCOLTONE, // CMYK TRUMATCH, // CMYK TOYO, // LAB LAB, GRAYSCALE, HKS, // CMYK DIC, // LAB TOTAL_INK, MONITOR_RGB, DUOTONE, OPACITY, ANPA = 3000 // LAB }; } // EFFECTS enum psd_gradient_style { psd_gradient_style_linear, // 'Lnr ' psd_gradient_style_radial, // 'Rdl ' psd_gradient_style_angle, // 'Angl' psd_gradient_style_reflected, // 'Rflc' psd_gradient_style_diamond // 'Dmnd' }; enum psd_color_stop_type { psd_color_stop_type_foreground_color, // 'FrgC' psd_color_stop_type_background_Color, // 'BckC' psd_color_stop_type_user_stop // 'UsrS' }; enum psd_technique_type { psd_technique_softer, psd_technique_precise, psd_technique_slope_limit, }; enum psd_stroke_position { psd_stroke_outside, psd_stroke_inside, psd_stroke_center }; enum psd_fill_type { psd_fill_solid_color, psd_fill_gradient, psd_fill_pattern, }; enum psd_glow_source { psd_glow_center, psd_glow_edge, }; enum psd_bevel_style { psd_bevel_outer_bevel, psd_bevel_inner_bevel, psd_bevel_emboss, psd_bevel_pillow_emboss, psd_bevel_stroke_emboss, }; enum psd_direction { psd_direction_up, psd_direction_down }; enum psd_section_type { psd_other = 0, psd_open_folder, psd_closed_folder, psd_bounding_divider }; // GRADIENT MAP // Each color stop struct psd_gradient_color_stop { qint32 location; // Location of color stop qint32 midpoint; // Midpoint of color stop QColor actual_color; psd_color_stop_type color_stop_type; }; // Each transparency stop struct psd_gradient_transparency_stop { qint32 location; // Location of transparency stop qint32 midpoint; // Midpoint of transparency stop qint8 opacity; // Opacity of transparency stop }; // Gradient settings (Photoshop 6.0) struct psd_layer_gradient_map { bool reverse; // Is gradient reverse bool dithered; // Is gradient dithered qint32 name_length; quint16 *name; // Name of the gradient: Unicode string, padded qint8 number_color_stops; // Number of color stops to follow psd_gradient_color_stop * color_stop; qint8 number_transparency_stops;// Number of transparency stops to follow psd_gradient_transparency_stop * transparency_stop; qint8 expansion_count; // Expansion count ( = 2 for Photoshop 6.0) qint8 interpolation; // Interpolation if length above is non-zero qint8 length; // Length (= 32 for Photoshop 6.0) qint8 mode; // Mode for this gradient qint32 random_number_seed; // Random number seed qint8 showing_transparency_flag;// Flag for showing transparency qint8 using_vector_color_flag;// Flag for using vector color qint32 roughness_factor; // Roughness factor QColor min_color; QColor max_color; QColor lookup_table[256]; }; struct psd_gradient_color { qint32 smoothness; qint32 name_length; quint16 * name; // Name of the gradient: Unicode string, padded qint8 number_color_stops; // Number of color stops to follow psd_gradient_color_stop * color_stop; qint8 number_transparency_stops;// Number of transparency stops to follow psd_gradient_transparency_stop *transparency_stop; }; struct psd_pattern { psd_color_mode color_mode = Bitmap; // The image mode of the file. quint8 height = 0; // Point: vertical, 2 bytes and horizontal, 2 bytes quint8 width = 0; QString name; QString uuid; qint32 version = 0; quint8 top = 0; // Rectangle: top, left, bottom, right quint8 left = 0; quint8 bottom = 0; quint8 right = 0; qint32 max_channel = 0; // Max channels qint32 channel_number = 0; QVector color_table; }; struct psd_layer_effects_context { psd_layer_effects_context() : keep_original(false) { } bool keep_original; }; #define PSD_LOOKUP_TABLE_SIZE 256 // dsdw, isdw: http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/PhotoshopFileFormats.htm#50577409_22203 class KRITAPSD_EXPORT psd_layer_effects_shadow_base { public: psd_layer_effects_shadow_base() : m_invertsSelection(false) , m_edgeHidden(true) , m_effectEnabled(false) , m_blendMode(COMPOSITE_MULT) , m_color(Qt::black) , m_nativeColor(Qt::black) , m_opacity(75) , m_angle(120) , m_useGlobalLight(true) , m_distance(21) , m_spread(0) , m_size(21) , m_antiAliased(0) , m_noise(0) , m_knocksOut(false) , m_fillType(psd_fill_solid_color) , m_technique(psd_technique_softer) , m_range(100) , m_jitter(0) , m_gradient(0) { for(int i = 0; i < PSD_LOOKUP_TABLE_SIZE; ++i) { m_contourLookupTable[i] = i; } } virtual ~psd_layer_effects_shadow_base() { } QPoint calculateOffset(const psd_layer_effects_context *context) const; void setEffectEnabled(bool value) { m_effectEnabled = value; } bool effectEnabled() const { return m_effectEnabled; } QString blendMode() const { return m_blendMode; } QColor color() const { return m_color; } QColor nativeColor() const { return m_nativeColor; } qint32 opacity() const { return m_opacity; } qint32 angle() const { return m_angle; } bool useGlobalLight() const { return m_useGlobalLight; } qint32 distance() const { return m_distance; } qint32 spread() const { return m_spread; } qint32 size() const { return m_size; } const quint8* contourLookupTable() const { return m_contourLookupTable; } bool antiAliased() const { return m_antiAliased; } qint32 noise() const { return m_noise; } bool knocksOut() const { return m_knocksOut; } bool invertsSelection() const { return m_invertsSelection; } bool edgeHidden() const { return m_edgeHidden; } psd_fill_type fillType() const { return m_fillType; } psd_technique_type technique() const { return m_technique; } qint32 range() const { return m_range; } qint32 jitter() const { return m_jitter; } KoAbstractGradientSP gradient() const { return m_gradient; } public: void setBlendMode(QString value) { m_blendMode = value; } void setColor(QColor value) { m_color = value; } void setNativeColor(QColor value) { m_nativeColor = value; } void setOpacity(qint32 value) { m_opacity = value; } void setAngle(qint32 value) { m_angle = value; } void setUseGlobalLight(bool value) { m_useGlobalLight = value; } void setDistance(qint32 value) { m_distance = value; } void setSpread(qint32 value) { m_spread = value; } void setSize(qint32 value) { m_size = value; } void setContourLookupTable(const quint8* value) { memcpy(m_contourLookupTable, value, PSD_LOOKUP_TABLE_SIZE * sizeof(quint8)); } void setAntiAliased(bool value) { m_antiAliased = value; } void setNoise(qint32 value) { m_noise = value; } void setKnocksOut(bool value) { m_knocksOut = value; } void setInvertsSelection(bool value) { m_invertsSelection = value; } void setEdgeHidden(bool value) { m_edgeHidden = value; } void setFillType(psd_fill_type value) { m_fillType = value; } void setTechnique(psd_technique_type value) { m_technique = value; } void setRange(qint32 value) { m_range = value; } void setJitter(qint32 value) { m_jitter = value; } void setGradient(KoAbstractGradientSP value) { m_gradient = value; } virtual void scaleLinearSizes(qreal scale) { m_distance *= scale; m_size *= scale; } private: // internal bool m_invertsSelection; bool m_edgeHidden; private: bool m_effectEnabled; // Effect enabled QString m_blendMode; // already in Krita format! QColor m_color; QColor m_nativeColor; qint32 m_opacity; // Opacity as a percent (0...100) qint32 m_angle; // Angle in degrees bool m_useGlobalLight; // Use this angle in all of the layer effects qint32 m_distance; // Distance in pixels qint32 m_spread; // Intensity as a percent qint32 m_size; // Blur value in pixels quint8 m_contourLookupTable[PSD_LOOKUP_TABLE_SIZE]; bool m_antiAliased; qint32 m_noise; bool m_knocksOut; // for Outer/Inner Glow psd_fill_type m_fillType; psd_technique_type m_technique; qint32 m_range; qint32 m_jitter; KoAbstractGradientSP m_gradient; }; class KRITAPSD_EXPORT psd_layer_effects_shadow_common : public psd_layer_effects_shadow_base { public: /// FIXME: 'using' is not supported by MSVC, so please refactor in /// some other way to ensure that the setters are not used /// in the classes we don't want // using psd_layer_effects_shadow_base::setBlendMode; // using psd_layer_effects_shadow_base::setColor; // using psd_layer_effects_shadow_base::setOpacity; // using psd_layer_effects_shadow_base::setAngle; // using psd_layer_effects_shadow_base::setUseGlobalLight; // using psd_layer_effects_shadow_base::setDistance; // using psd_layer_effects_shadow_base::setSpread; // using psd_layer_effects_shadow_base::setSize; // using psd_layer_effects_shadow_base::setContourLookupTable; // using psd_layer_effects_shadow_base::setAntiAliased; // using psd_layer_effects_shadow_base::setNoise; }; class KRITAPSD_EXPORT psd_layer_effects_drop_shadow : public psd_layer_effects_shadow_common { public: /// FIXME: 'using' is not supported by MSVC, so please refactor in /// some other way to ensure that the setters are not used /// in the classes we don't want //using psd_layer_effects_shadow_base::setKnocksOut; }; // isdw: http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/PhotoshopFileFormats.htm#50577409_22203 class KRITAPSD_EXPORT psd_layer_effects_inner_shadow : public psd_layer_effects_shadow_common { public: psd_layer_effects_inner_shadow() { setKnocksOut(true); setInvertsSelection(true); setEdgeHidden(false); } }; class KRITAPSD_EXPORT psd_layer_effects_glow_common : public psd_layer_effects_shadow_base { public: psd_layer_effects_glow_common() { setKnocksOut(true); setDistance(0); setBlendMode(COMPOSITE_LINEAR_DODGE); setColor(Qt::white); } /// FIXME: 'using' is not supported by MSVC, so please refactor in /// some other way to ensure that the setters are not used /// in the classes we don't want // using psd_layer_effects_shadow_base::setBlendMode; // using psd_layer_effects_shadow_base::setColor; // using psd_layer_effects_shadow_base::setOpacity; // using psd_layer_effects_shadow_base::setSpread; // using psd_layer_effects_shadow_base::setSize; // using psd_layer_effects_shadow_base::setContourLookupTable; // using psd_layer_effects_shadow_base::setAntiAliased; // using psd_layer_effects_shadow_base::setNoise; // using psd_layer_effects_shadow_base::setFillType; // using psd_layer_effects_shadow_base::setTechnique; // using psd_layer_effects_shadow_base::setRange; // using psd_layer_effects_shadow_base::setJitter; // using psd_layer_effects_shadow_base::setGradient; }; // oglw: http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/PhotoshopFileFormats.htm#50577409_25738 class KRITAPSD_EXPORT psd_layer_effects_outer_glow : public psd_layer_effects_glow_common { }; // iglw: http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/PhotoshopFileFormats.htm#50577409_27692 class KRITAPSD_EXPORT psd_layer_effects_inner_glow : public psd_layer_effects_glow_common { public: psd_layer_effects_inner_glow() : m_source(psd_glow_edge) { setInvertsSelection(true); setEdgeHidden(false); } psd_glow_source source() const { return m_source; } void setSource(psd_glow_source value) { m_source = value; } private: psd_glow_source m_source; }; struct psd_layer_effects_satin : public psd_layer_effects_shadow_base { psd_layer_effects_satin() { setInvert(false); setUseGlobalLight(false); setDistance(8); setSize(7); setSpread(0); setKnocksOut(true); setEdgeHidden(false); setBlendMode(COMPOSITE_LINEAR_BURN); } /// FIXME: 'using' is not supported by MSVC, so please refactor in /// some other way to ensure that the setters are not used /// in the classes we don't want // using psd_layer_effects_shadow_base::setBlendMode; // using psd_layer_effects_shadow_base::setColor; // using psd_layer_effects_shadow_base::setOpacity; // // NOTE: no global light setting explicitly! // using psd_layer_effects_shadow_base::setAngle; // using psd_layer_effects_shadow_base::setDistance; // using psd_layer_effects_shadow_base::setSize; // using psd_layer_effects_shadow_base::setContourLookupTable; // using psd_layer_effects_shadow_base::setAntiAliased; bool invert() const { return m_invert; } void setInvert(bool value) { m_invert = value; } private: bool m_invert; }; struct psd_pattern_info { qint32 name_length; quint16 * name; quint8 identifier[256]; }; // bevl: http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/PhotoshopFileFormats.htm#50577409_31889 struct psd_layer_effects_bevel_emboss : public psd_layer_effects_shadow_base { psd_layer_effects_bevel_emboss() : m_style(psd_bevel_inner_bevel), m_technique(psd_technique_softer), m_depth(100), m_direction(psd_direction_up), m_soften(0), m_altitude(30), m_glossAntiAliased(false), m_highlightBlendMode(COMPOSITE_SCREEN), m_highlightColor(Qt::white), m_highlightOpacity(75), m_shadowBlendMode(COMPOSITE_MULT), m_shadowColor(Qt::black), m_shadowOpacity(75), m_contourEnabled(false), m_contourRange(100), m_textureEnabled(false), m_texturePattern(0), m_textureScale(100), m_textureDepth(100), m_textureInvert(false), m_textureAlignWithLayer(true), m_textureHorizontalPhase(0), m_textureVerticalPhase(0) { for(int i = 0; i < PSD_LOOKUP_TABLE_SIZE; ++i) { m_glossContourLookupTable[i] = i; } } /// FIXME: 'using' is not supported by MSVC, so please refactor in /// some other way to ensure that the setters are not used /// in the classes we don't want // using psd_layer_effects_shadow_base::setSize; // using psd_layer_effects_shadow_base::setAngle; // using psd_layer_effects_shadow_base::setUseGlobalLight; // using psd_layer_effects_shadow_base::setContourLookupTable; // using psd_layer_effects_shadow_base::setAntiAliased; psd_bevel_style style() const { return m_style; } void setStyle(psd_bevel_style value) { m_style = value; } psd_technique_type technique() const { return m_technique; } void setTechnique(psd_technique_type value) { m_technique = value; } int depth() const { return m_depth; } void setDepth(int value) { m_depth = value; } psd_direction direction() const { return m_direction; } void setDirection(psd_direction value) { m_direction = value; } int soften() const { return m_soften; } void setSoften(int value) { m_soften = value; } int altitude() const { return m_altitude; } void setAltitude(int value) { m_altitude = value; } const quint8* glossContourLookupTable() const { return m_glossContourLookupTable; } void setGlossContourLookupTable(const quint8 *value) { memcpy(m_glossContourLookupTable, value, PSD_LOOKUP_TABLE_SIZE * sizeof(quint8)); } bool glossAntiAliased() const { return m_glossAntiAliased; } void setGlossAntiAliased(bool value) { m_glossAntiAliased = value; } QString highlightBlendMode() const { return m_highlightBlendMode; } void setHighlightBlendMode(QString value) { m_highlightBlendMode = value; } QColor highlightColor() const { return m_highlightColor; } void setHighlightColor(QColor value) { m_highlightColor = value; } qint32 highlightOpacity() const { return m_highlightOpacity; } void setHighlightOpacity(qint32 value) { m_highlightOpacity = value; } QString shadowBlendMode() const { return m_shadowBlendMode; } void setShadowBlendMode(QString value) { m_shadowBlendMode = value; } QColor shadowColor() const { return m_shadowColor; } void setShadowColor(QColor value) { m_shadowColor = value; } qint32 shadowOpacity() const { return m_shadowOpacity; } void setShadowOpacity(qint32 value) { m_shadowOpacity = value; } bool contourEnabled() const { return m_contourEnabled; } void setContourEnabled(bool value) { m_contourEnabled = value; } int contourRange() const { return m_contourRange; } void setContourRange(int value) { m_contourRange = value; } bool textureEnabled() const { return m_textureEnabled; } void setTextureEnabled(bool value) { m_textureEnabled = value; } - KoPattern* texturePattern() const { + KoPatternSP texturePattern() const { return m_texturePattern; } - void setTexturePattern(KoPattern *value) { + void setTexturePattern(KoPatternSP value) { m_texturePattern = value; } int textureScale() const { return m_textureScale; } void setTextureScale(int value) { m_textureScale = value; } int textureDepth() const { return m_textureDepth; } void setTextureDepth(int value) { m_textureDepth = value; } bool textureInvert() const { return m_textureInvert; } void setTextureInvert(bool value) { m_textureInvert = value; } bool textureAlignWithLayer() const { return m_textureAlignWithLayer; } void setTextureAlignWithLayer(bool value) { m_textureAlignWithLayer = value; } void setTexturePhase(const QPointF &phase) { m_textureHorizontalPhase = phase.x(); m_textureVerticalPhase = phase.y(); } QPointF texturePhase() const { return QPointF(m_textureHorizontalPhase, m_textureVerticalPhase); } int textureHorizontalPhase() const { return m_textureHorizontalPhase; } void setTextureHorizontalPhase(int value) { m_textureHorizontalPhase = value; } int textureVerticalPhase() const { return m_textureVerticalPhase; } void setTextureVerticalPhase(int value) { m_textureVerticalPhase = value; } void scaleLinearSizes(qreal scale) override { psd_layer_effects_shadow_base::scaleLinearSizes(scale); m_soften *= scale; m_textureScale *= scale; } private: psd_bevel_style m_style; psd_technique_type m_technique; int m_depth; psd_direction m_direction; // Up or down int m_soften; // Blur value in pixels. int m_altitude; quint8 m_glossContourLookupTable[256]; bool m_glossAntiAliased; QString m_highlightBlendMode; // already in Krita format QColor m_highlightColor; qint32 m_highlightOpacity; // Highlight opacity as a percent QString m_shadowBlendMode; // already in Krita format QColor m_shadowColor; qint32 m_shadowOpacity; // Shadow opacity as a percent bool m_contourEnabled; int m_contourRange; bool m_textureEnabled; - KoPattern *m_texturePattern; + KoPatternSP m_texturePattern; int m_textureScale; int m_textureDepth; bool m_textureInvert; bool m_textureAlignWithLayer; int m_textureHorizontalPhase; // 0..100% int m_textureVerticalPhase; // 0..100% }; struct psd_layer_effects_overlay_base : public psd_layer_effects_shadow_base { psd_layer_effects_overlay_base() : m_scale(100), m_alignWithLayer(true), m_reverse(false), m_style(psd_gradient_style_linear), m_gradientXOffset(0), m_gradientYOffset(0), m_pattern(0), m_horizontalPhase(0), m_verticalPhase(0) { setUseGlobalLight(false); } /// FIXME: 'using' is not supported by MSVC, so please refactor in /// some other way to ensure that the setters are not used /// in the classes we don't want // using psd_layer_effects_shadow_base::setBlendMode; // using psd_layer_effects_shadow_base::setOpacity; int scale() const { return m_scale; } bool alignWithLayer() const { return m_alignWithLayer; } bool reverse() const { return m_reverse; } psd_gradient_style style() const { return m_style; } int gradientXOffset() const { return m_gradientXOffset; } int gradientYOffset() const { return m_gradientYOffset; } - KoPattern* pattern() const { + KoPatternSP pattern() const { return m_pattern; } int horizontalPhase() const { return m_horizontalPhase; } int verticalPhase() const { return m_verticalPhase; } // refactor that public: void setScale(int value) { m_scale = value; } void setAlignWithLayer(bool value) { m_alignWithLayer = value; } void setReverse(bool value) { m_reverse = value; } void setStyle(psd_gradient_style value) { m_style = value; } void setGradientOffset(const QPointF &pt) { m_gradientXOffset = qRound(pt.x()); m_gradientYOffset = qRound(pt.y()); } QPointF gradientOffset() const { return QPointF(m_gradientXOffset, m_gradientYOffset); } - void setPattern(KoPattern *value) { + void setPattern(KoPatternSP value) { m_pattern = value; } void setPatternPhase(const QPointF &phase) { m_horizontalPhase = phase.x(); m_verticalPhase = phase.y(); } QPointF patternPhase() const { return QPointF(m_horizontalPhase, m_verticalPhase); } void scaleLinearSizes(qreal scale) override { psd_layer_effects_shadow_base::scaleLinearSizes(scale); m_scale *= scale; } private: // Gradient+Pattern int m_scale; bool m_alignWithLayer; // Gradient bool m_reverse; psd_gradient_style m_style; int m_gradientXOffset; // 0..100% int m_gradientYOffset; // 0..100% // Pattern - KoPattern *m_pattern; + KoPatternSP m_pattern; int m_horizontalPhase; // 0..100% int m_verticalPhase; // 0..100% protected: /// FIXME: 'using' is not supported by MSVC, so please refactor in /// some other way to ensure that the setters are not used /// in the classes we don't want // must be called in the derived classes' c-tor // using psd_layer_effects_shadow_base::setFillType; }; // sofi: http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/PhotoshopFileFormats.htm#50577409_70055 struct psd_layer_effects_color_overlay : public psd_layer_effects_overlay_base { psd_layer_effects_color_overlay() { setFillType(psd_fill_solid_color); setColor(Qt::white); } /// FIXME: 'using' is not supported by MSVC, so please refactor in /// some other way to ensure that the setters are not used /// in the classes we don't want // using psd_layer_effects_shadow_base::setColor; }; struct psd_layer_effects_gradient_overlay : public psd_layer_effects_overlay_base { psd_layer_effects_gradient_overlay() { setFillType(psd_fill_gradient); setAngle(90); setReverse(false); setScale(100); setAlignWithLayer(true); setStyle(psd_gradient_style_linear); } public: /// FIXME: 'using' is not supported by MSVC, so please refactor in /// some other way to ensure that the setters are not used /// in the classes we don't want // using psd_layer_effects_shadow_base::setGradient; // using psd_layer_effects_shadow_base::setAngle; // using psd_layer_effects_overlay_base::setReverse; // using psd_layer_effects_overlay_base::setScale; // using psd_layer_effects_overlay_base::setAlignWithLayer; // using psd_layer_effects_overlay_base::setStyle; // using psd_layer_effects_overlay_base::setGradientOffset; // using psd_layer_effects_overlay_base::gradientOffset; }; struct psd_layer_effects_pattern_overlay : public psd_layer_effects_overlay_base { psd_layer_effects_pattern_overlay() { setFillType(psd_fill_pattern); setScale(100); setAlignWithLayer(true); } /// FIXME: 'using' is not supported by MSVC, so please refactor in /// some other way to ensure that the setters are not used /// in the classes we don't want // using psd_layer_effects_overlay_base::setScale; // using psd_layer_effects_overlay_base::setAlignWithLayer; // using psd_layer_effects_overlay_base::setPattern; // using psd_layer_effects_overlay_base::setPatternPhase; // using psd_layer_effects_overlay_base::patternPhase; private: // These are unused /*int m_scale; bool m_alignWithLayer; - KoPattern *m_pattern; + KoPatternSP m_pattern; int m_horizontalPhase; int m_verticalPhase;*/ }; struct psd_layer_effects_stroke : public psd_layer_effects_overlay_base { psd_layer_effects_stroke() : m_position(psd_stroke_outside) { setFillType(psd_fill_solid_color); setColor(Qt::black); setAngle(90); setReverse(false); setScale(100); setAlignWithLayer(true); setStyle(psd_gradient_style_linear); setScale(100); setAlignWithLayer(true); } /// FIXME: 'using' is not supported by MSVC, so please refactor in /// some other way to ensure that the setters are not used /// in the classes we don't want // using psd_layer_effects_shadow_base::setFillType; // using psd_layer_effects_shadow_base::setSize; // using psd_layer_effects_shadow_base::setColor; // using psd_layer_effects_shadow_base::setGradient; // using psd_layer_effects_shadow_base::setAngle; // using psd_layer_effects_overlay_base::setReverse; // using psd_layer_effects_overlay_base::setScale; // using psd_layer_effects_overlay_base::setAlignWithLayer; // using psd_layer_effects_overlay_base::setStyle; // using psd_layer_effects_overlay_base::setGradientOffset; // using psd_layer_effects_overlay_base::gradientOffset; // using psd_layer_effects_overlay_base::setPattern; // using psd_layer_effects_overlay_base::setPatternPhase; // using psd_layer_effects_overlay_base::patternPhase; psd_stroke_position position() const { return m_position; } void setPosition(psd_stroke_position value) { m_position = value; } private: psd_stroke_position m_position; }; /** * Convert PsdColorMode to pigment colormodelid and colordepthid. * @see KoColorModelStandardIds * * @return a QPair containing ColorModelId and ColorDepthID */ QPair KRITAPSD_EXPORT psd_colormode_to_colormodelid(psd_color_mode colormode, quint16 channelDepth); /** * Convert the Photoshop blend mode strings to Pigment compositeop id's */ QString KRITAPSD_EXPORT psd_blendmode_to_composite_op(const QString& blendmode); QString KRITAPSD_EXPORT composite_op_to_psd_blendmode(const QString& compositeOp); #endif // PSD_H diff --git a/libs/psd/psd_pattern.cpp b/libs/psd/psd_pattern.cpp index e2941bb5ab..2bcf98feb0 100644 --- a/libs/psd/psd_pattern.cpp +++ b/libs/psd/psd_pattern.cpp @@ -1,212 +1,212 @@ /* * Copyright (c) 2014 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 "psd_pattern.h" #include "psd_utils.h" #include "compression.h" #include #include struct PsdPattern::Private { - KoPattern *patternResource; + KoPatternSP patternResource; }; PsdPattern::PsdPattern() : d(new Private()) { d->patternResource = 0; } PsdPattern::~PsdPattern() { delete d; } -void PsdPattern::setPattern(KoPattern *pattern) +void PsdPattern::setPattern(KoPatternSP pattern) { d->patternResource = pattern; } -KoPattern *PsdPattern::pattern() const +KoPatternSP PsdPattern::pattern() const { return d->patternResource; } bool psd_write_pattern(QIODevice *io) { Q_UNUSED(io); return false; } bool psd_read_pattern(QIODevice *io) { quint32 pattern_length; psd_pattern pattern; psdread(io, &pattern_length); pattern_length = (pattern_length + 3) & ~3; psdread(io, &pattern.version); if (pattern.version != 1) return false; psdread(io, (quint32*)&pattern.color_mode); psdread(io, &pattern.height); psdread(io, &pattern.width); psdread_unicodestring(io, pattern.name); psdread_pascalstring(io, pattern.uuid, 2); if (pattern.color_mode == Indexed) { pattern.color_table.reserve(256); quint8 r; quint8 g; quint8 b; for (int i = 0; i < 256; ++i) { psdread(io, &r); psdread(io, &g); psdread(io, &b); pattern.color_table.append(qRgb(r, g, b)); } } // Now load the virtual memory array psdread(io, &pattern.version); if (pattern.version != 3) return false; quint32 vm_array_length; psdread(io, &vm_array_length); psdread(io, &pattern.top); psdread(io, &pattern.left); psdread(io, &pattern.bottom); psdread(io, &pattern.right); QImage img; if (pattern.color_mode == Indexed) { img = QImage(pattern.width, pattern.height, QImage::Format_Indexed8); img.setColorTable(pattern.color_table); } else { img = QImage(pattern.width, pattern.height, QImage::Format_ARGB32); } qint32 max_channels; psdread(io, &max_channels); QVector channelData; for (int i = 0; i < max_channels; ++i) { quint32 written; qint32 len; quint32 pixel_depth1; quint32 top; quint32 left; quint32 bottom; quint32 right; quint16 pixel_depth2; quint8 compression_mode; psdread(io, &written); psdread(io, &len); len -= 4 + 4 * 4 + 2 + 1; if (len < 0) { continue; } if (written > 0) { // Note: channel_number is not read from the file, so always equals 0. // Other behavior may be implemented later. if (pattern.channel_number == 0) { psdread(io, &pixel_depth1); } else { quint32 d; psdread(io, &d); } } else { quint32 d; psdread(io, &d); } psdread(io, &top); psdread(io, &left); psdread(io, &bottom); psdread(io, &right); psdread(io, &pixel_depth2); psdread(io, &compression_mode); quint32 per_channel_length = 0; if (written > 0) { if (pattern.channel_number == 0) { qint32 pixels; qint32 length; pixels = length = pattern.width * pattern.height; switch(pixel_depth1) { case 1: length = (pattern.width + 7) / 8 * pattern.height; break; case 8: break; case 16: length *= 2; pixels *= 2; break; default: dbgKrita << "Wrong depth for pattern"; return false; } per_channel_length = length; Q_UNUSED(per_channel_length); // wtf!? switch(pattern.color_mode) { case Bitmap: case Indexed: break; case Grayscale: case DuoTone: length *= 2; break; case RGB: length *= 4; break; case CMYK: length *= 5; break; case Lab: length *= 4; break; case MultiChannel: length *= 4; break; default: dbgKrita << "Impossible color mode" << pattern.color_mode; return false; } QByteArray ba = io->read(len); channelData << Compression::uncompress(length, ba, (Compression::CompressionType)compression_mode); } } } return true; } diff --git a/libs/psd/psd_pattern.h b/libs/psd/psd_pattern.h index d9aed40628..e7ab0b6afe 100644 --- a/libs/psd/psd_pattern.h +++ b/libs/psd/psd_pattern.h @@ -1,41 +1,41 @@ /* * Copyright (c) 2014 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. */ #ifndef PSD_PATTERN_H #define PSD_PATTERN_H #include "psd.h" #include #include class KRITAPSD_EXPORT PsdPattern { public: PsdPattern(); ~PsdPattern(); - void setPattern(KoPattern *pattern); - KoPattern *pattern() const; + void setPattern(KoPatternSP pattern); + KoPatternSP pattern() const; bool psd_write_pattern(QIODevice* io); bool psd_read_pattern(QIODevice* io); private: struct Private; Private * const d; }; #endif // PSD_PATTERN_H diff --git a/libs/resources/KisAbrStorage.cpp b/libs/resources/KisAbrStorage.cpp index 257b4fa12c..6063c5794d 100644 --- a/libs/resources/KisAbrStorage.cpp +++ b/libs/resources/KisAbrStorage.cpp @@ -1,87 +1,87 @@ /* * Copyright (C) 2018 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KisAbrStorage.h" #include "KisResourceStorage.h" class AbrTagIterator : public KisResourceStorage::TagIterator { public: AbrTagIterator(const QString &location, const QString &resourceType) : m_location(location) , m_resourceType(resourceType) {} bool hasNext() const override {return false; } void next() const override {} QString url() const override { return QString(); } QString name() const override { return QString(); } QString comment() const override {return QString(); } KisTagSP tag() const override { return 0; } private: QString m_location; QString m_resourceType; }; class AbrIterator : public KisResourceStorage::ResourceIterator { public: bool hasNext() const override {return false; } void next() const override {} QString url() const override { return QString(); } QString type() const override { return QString(); } QDateTime lastModified() const override { return QDateTime(); } /// This only loads the resource when called KoResourceSP resource() const override { return 0; } }; KisAbrStorage::KisAbrStorage(const QString &location) : KisStoragePlugin(location) { } KisAbrStorage::~KisAbrStorage() { } -KisResourceStorage::ResourceItem KisAbrStorage::resourceItem(const QString &url) +KisResourceStorage::ResourceItem KisAbrStorage::resourceItem(const QString &/*url*/) { return KisResourceStorage::ResourceItem(); } -KoResourceSP KisAbrStorage::resource(const QString &url) +KoResourceSP KisAbrStorage::resource(const QString &/*url*/) { return 0; } -QSharedPointer KisAbrStorage::resources(const QString &resourceType) +QSharedPointer KisAbrStorage::resources(const QString &/*resourceType*/) { return QSharedPointer(new AbrIterator); } QSharedPointer KisAbrStorage::tags(const QString &resourceType) { return QSharedPointer(new AbrTagIterator(location(), resourceType)); } diff --git a/libs/resources/KisAslStorage.cpp b/libs/resources/KisAslStorage.cpp index 67f96eefb7..765ce55dfa 100644 --- a/libs/resources/KisAslStorage.cpp +++ b/libs/resources/KisAslStorage.cpp @@ -1,89 +1,89 @@ /* * Copyright (C) 2018 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KisAslStorage.h" #include class AslTagIterator : public KisResourceStorage::TagIterator { public: AslTagIterator(const QString &location, const QString &resourceType) : m_location(location) , m_resourceType(resourceType) {} bool hasNext() const override {return false; } void next() const override {} QString url() const override { return QString(); } QString name() const override { return QString(); } QString comment() const override {return QString(); } KisTagSP tag() const override { return 0; } private: QString m_location; QString m_resourceType; }; class AslIterator : public KisResourceStorage::ResourceIterator { public: bool hasNext() const override {return false; } void next() const override {} QString url() const override { return QString(); } QString type() const override { return QString(); } QDateTime lastModified() const override { return QDateTime(); } /// This only loads the resource when called KoResourceSP resource() const override { return 0; } }; KisAslStorage::KisAslStorage(const QString &location) : KisStoragePlugin(location) { } KisAslStorage::~KisAslStorage() { } -KisResourceStorage::ResourceItem KisAslStorage::resourceItem(const QString &url) +KisResourceStorage::ResourceItem KisAslStorage::resourceItem(const QString &/*url*/) { return KisResourceStorage::ResourceItem(); } -KoResourceSP KisAslStorage::resource(const QString &url) +KoResourceSP KisAslStorage::resource(const QString &/*url*/) { return 0; } -QSharedPointer KisAslStorage::resources(const QString &resourceType) +QSharedPointer KisAslStorage::resources(const QString &/*resourceType*/) { return QSharedPointer(new AslIterator); } QSharedPointer KisAslStorage::tags(const QString &resourceType) { return QSharedPointer(new AslTagIterator(location(), resourceType)); } diff --git a/libs/resources/KoResource.h b/libs/resources/KoResource.h index e0eaacb70c..9b200f9d23 100644 --- a/libs/resources/KoResource.h +++ b/libs/resources/KoResource.h @@ -1,133 +1,134 @@ /* This file is part of the KDE project Copyright (c) 2003 Patrick Julien Copyright (c) 2005 Boudewijn Rempt 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 KORESOURCE_H #define KORESOURCE_H #include #include #include #include class QDomDocument; class QDomElement; /** * The KoResource class provides a representation of resources. This * includes, but not limited to, brushes and patterns. */ class KRITARESOURCES_EXPORT KoResource { public: /** * Creates a new KoResource object using @p filename. No file is opened * in the constructor, you have to call load. * * @param filename the file name to save and load from. */ explicit KoResource(const QString &filename); virtual ~KoResource(); bool operator ==(const KoResource &other) const { return other.md5() == md5(); } public: /** * Load this resource. * @return true if loading the resource succeeded. */ virtual bool load() = 0; virtual bool loadFromDevice(QIODevice *dev) = 0; /** * Save this resource. *@return true if saving the resource succeeded. */ virtual bool save() = 0; virtual bool saveToDevice(QIODevice* dev) const; /** * @returns a QImage thumbnail image representing this resource. * * This image could be null. The image can be in any valid format. */ QImage image() const; void setImage(const QImage &image); /// @return the md5sum calculated over the contents of the resource. QByteArray md5() const; /// @returns true if resource can be removed by the user bool removable() const; /// @return the full path to this resource QString filename() const; void setFilename(const QString& filename); /// @return the name of the file without the path QString shortFilename() const; /// @return the user-visible name of the resource QString name() const; void setName(const QString& name); /// @return true if the resource is ready for use bool valid() const; void setValid(bool valid); /// @return the default file extension which should be used when saving the resource virtual QString defaultFileExtension() const; /// @return true if the resource is permanent and can't be removed by the user bool permanent() const; void setPermanent(bool permanent); protected: /// override generateMD5 and in your resource subclass virtual QByteArray generateMD5() const; /// call this when the contents of the resource change so the md5 needs to be recalculated void setMD5(const QByteArray &md5); protected: KoResource(const KoResource &rhs); private: struct Private; Private* const d; }; static inline bool operator==(const KoResource &resource1, const KoResource &resource2) { return (resource1.md5() == resource2.md5()); } static inline uint qHash(const KoResource &resource) { return qHash(resource.md5()); } typedef QSharedPointer KoResourceSP; +Q_DECLARE_METATYPE(QSharedPointer) #endif // KORESOURCE_H_ diff --git a/libs/resources/KoResourceBundle.cpp b/libs/resources/KoResourceBundle.cpp index b8df8ac306..8f1eb89e2a 100644 --- a/libs/resources/KoResourceBundle.cpp +++ b/libs/resources/KoResourceBundle.cpp @@ -1,534 +1,534 @@ /* * Copyright (c) 2014 Victor Lafon metabolic.ewilan@hotmail.fr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoResourceBundle.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "KoResourceBundleManifest.h" #include #include #include #include #include #include #include "KisStoragePlugin.h" #include "KisResourceLoaderRegistry.h" #include #include KoResourceBundle::KoResourceBundle(QString const& fileName) : KoResource(fileName), m_bundleVersion("1") { setName(QFileInfo(fileName).baseName()); m_metadata[KisStoragePlugin::s_meta_generator] = "Krita (" + KritaVersionWrapper::versionString(true) + ")"; } KoResourceBundle::~KoResourceBundle() { } QString KoResourceBundle::defaultFileExtension() const { return QString(".bundle"); } bool KoResourceBundle::load() { if (filename().isEmpty()) return false; QScopedPointer resourceStore(KoStore::createStore(filename(), KoStore::Read, "application/x-krita-resourcebundle", KoStore::Zip)); if (!resourceStore || resourceStore->bad()) { qWarning() << "Could not open store on bundle" << filename(); setValid(false); return false; } else { m_metadata.clear(); if (resourceStore->open("META-INF/manifest.xml")) { if (!m_manifest.load(resourceStore->device())) { qWarning() << "Could not open manifest for bundle" << filename(); return false; } resourceStore->close(); Q_FOREACH (KoResourceBundleManifest::ResourceReference ref, m_manifest.files()) { if (!resourceStore->open(ref.resourcePath)) { qWarning() << "Bundle is broken. File" << ref.resourcePath << "is missing"; } else { resourceStore->close(); } } } else { qWarning() << "Could not load META-INF/manifest.xml"; return false; } bool versionFound = false; if (!readMetaData(resourceStore.data())) { qWarning() << "Could not load meta.xml"; return false; } if (resourceStore->open("preview.png")) { // Workaround for some OS (Debian, Ubuntu), where loading directly from the QIODevice // fails with "libpng error: IDAT: CRC error" QByteArray data = resourceStore->device()->readAll(); QBuffer buffer(&data); m_thumbnail.load(&buffer, "PNG"); resourceStore->close(); } else { qWarning() << "Could not open preview.png"; } /* * If no version is found it's an old bundle with md5 hashes to fix, or if some manifest resource entry * doesn't not correspond to a file the bundle is "broken", in both cases we need to recreate the bundle. */ if (!versionFound) { m_metadata.insert(KisStoragePlugin::s_meta_version, "1"); } setValid(true); setImage(m_thumbnail); } return true; } bool KoResourceBundle::loadFromDevice(QIODevice *) { return false; } -bool saveResourceToStore(KoResource *resource, KoStore *store, const QString &resType) +bool saveResourceToStore(KoResourceSP resource, KoStore *store, const QString &resType) { if (!resource) { qWarning() << "No Resource"; return false; } if (!resource->valid()) { qWarning() << "Resource is not valid"; return false; } if (!store || store->bad()) { qWarning() << "No Store or Store is Bad"; return false; } QByteArray ba; QBuffer buf; QFileInfo fi(resource->filename()); if (fi.exists() && fi.isReadable()) { QFile f(resource->filename()); if (!f.open(QFile::ReadOnly)) { qWarning() << "Could not open resource" << resource->filename(); return false; } ba = f.readAll(); if (ba.size() == 0) { qWarning() << "Resource is empty" << resource->filename(); return false; } f.close(); buf.setBuffer(&ba); } else { qWarning() << "Could not find the resource " << resource->filename() << " or it isn't readable"; return false; } if (!buf.open(QBuffer::ReadOnly)) { qWarning() << "Could not open buffer"; return false; } Q_ASSERT(!store->hasFile(resType + "/" + resource->shortFilename())); if (!store->open(resType + "/" + resource->shortFilename())) { qWarning() << "Could not open file in store for resource"; return false; } bool res = (store->write(buf.data()) == buf.size()); store->close(); return res; } bool KoResourceBundle::save() { if (filename().isEmpty()) return false; setMetaData(KisStoragePlugin::s_meta_dc_date, QDate::currentDate().toString("dd/MM/yyyy")); QDir bundleDir = KoResourcePaths::saveLocation("data", "bundles"); bundleDir.cdUp(); QScopedPointer store(KoStore::createStore(filename(), KoStore::Write, "application/x-krita-resourcebundle", KoStore::Zip)); if (!store || store->bad()) return false; // Q_FOREACH (const QString &resType, m_manifest.types()) { // if (resType == "gradients") { // KoResourceServer* gradientServer = KoResourceServerProvider::instance()->gradientServer(); // Q_FOREACH (const KoResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { - // KoResource *res = gradientServer->resourceByMD5(ref.md5sum); + // KoResourceSP res = gradientServer->resourceByMD5(ref.md5sum); // if (!res) res = gradientServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName()); // if (!saveResourceToStore(res, store.data(), "gradients")) { // if (res) { // qWarning() << "Could not save resource" << resType << res->name(); // } // else { // qWarning() << "could not find resource for" << QFileInfo(ref.resourcePath).fileName(); // } // } // } // } // else if (resType == "patterns") { // KoResourceServer* patternServer = KoResourceServerProvider::instance()->patternServer(); // Q_FOREACH (const KoResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { - // KoResource *res = patternServer->resourceByMD5(ref.md5sum); + // KoResourceSP res = patternServer->resourceByMD5(ref.md5sum); // if (!res) res = patternServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName()); // if (!saveResourceToStore(res, store.data(), "patterns")) { // if (res) { // qWarning() << "Could not save resource" << resType << res->name(); // } // else { // qWarning() << "could not find resource for" << QFileInfo(ref.resourcePath).fileName(); // } // } // } // } // else if (resType == "brushes") { // KisBrushResourceServer* brushServer = KisBrushServer::instance()->brushServer(); // Q_FOREACH (const KoResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { // KisBrushSP brush = brushServer->resourceByMD5(ref.md5sum); // if (!brush) brush = brushServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName()); - // KoResource *res = brush.data(); + // KoResourceSP res = brush.data(); // if (!saveResourceToStore(res, store.data(), "brushes")) { // if (res) { // qWarning() << "Could not save resource" << resType << res->name(); // } // else { // qWarning() << "could not find resource for" << QFileInfo(ref.resourcePath).fileName(); // } // } // } // } // else if (resType == "palettes") { // KoResourceServer* paletteServer = KoResourceServerProvider::instance()->paletteServer(); // Q_FOREACH (const KoResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { - // KoResource *res = paletteServer->resourceByMD5(ref.md5sum); + // KoResourceSP res = paletteServer->resourceByMD5(ref.md5sum); // if (!res) res = paletteServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName()); // if (!saveResourceToStore(res, store.data(), "palettes")) { // if (res) { // qWarning() << "Could not save resource" << resType << res->name(); // } // else { // qWarning() << "could not find resource for" << QFileInfo(ref.resourcePath).fileName(); // } // } // } // } // else if (resType == "workspaces") { // KoResourceServer< KisWorkspaceResource >* workspaceServer = KisResourceServerProvider::instance()->workspaceServer(); // Q_FOREACH (const KoResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { - // KoResource *res = workspaceServer->resourceByMD5(ref.md5sum); + // KoResourceSP res = workspaceServer->resourceByMD5(ref.md5sum); // if (!res) res = workspaceServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName()); // if (!saveResourceToStore(res, store.data(), "workspaces")) { // if (res) { // qWarning() << "Could not save resource" << resType << res->name(); // } // else { // qWarning() << "could not find resource for" << QFileInfo(ref.resourcePath).fileName(); // } // } // } // } // else if (resType == "paintoppresets") { // KisPaintOpPresetResourceServer* paintoppresetServer = KisResourceServerProvider::instance()->paintOpPresetServer(); // Q_FOREACH (const KoResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { // KisPaintOpPresetSP res = paintoppresetServer->resourceByMD5(ref.md5sum); // if (!res) res = paintoppresetServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName()); // if (!saveResourceToStore(res.data(), store.data(), "paintoppresets")) { // if (res) { // qWarning() << "Could not save resource" << resType << res->name(); // } // else { // qWarning() << "could not find resource for" << QFileInfo(ref.resourcePath).fileName(); // } // } // } // } // } if (!m_thumbnail.isNull()) { QByteArray byteArray; QBuffer buffer(&byteArray); m_thumbnail.save(&buffer, "PNG"); if (!store->open("preview.png")) qWarning() << "Could not open preview.png"; if (store->write(byteArray) != buffer.size()) qWarning() << "Could not write preview.png"; store->close(); } saveManifest(store); saveMetadata(store); store->finalize(); return true; } bool KoResourceBundle::saveToDevice(QIODevice */*dev*/) const { return false; } void KoResourceBundle::setMetaData(const QString &key, const QString &value) { m_metadata.insert(key, value); } const QString KoResourceBundle::metaData(const QString &key, const QString &defaultValue) const { if (m_metadata.contains(key)) { return m_metadata[key]; } else { return defaultValue; } } void KoResourceBundle::addResource(QString fileType, QString filePath, QStringList fileTagList, const QByteArray md5sum) { m_manifest.addResource(fileType, filePath, fileTagList, md5sum); } QList KoResourceBundle::getTagsList() { return QList::fromSet(m_bundletags); } QStringList KoResourceBundle::resourceTypes() const { return m_manifest.types(); } void KoResourceBundle::setThumbnail(QString filename) { if (QFileInfo(filename).exists()) { m_thumbnail = QImage(filename); m_thumbnail = m_thumbnail.scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation); } else { m_thumbnail = QImage(256, 256, QImage::Format_ARGB32); QPainter gc(&m_thumbnail); gc.fillRect(0, 0, 256, 256, Qt::red); gc.end(); } setImage(m_thumbnail); } void KoResourceBundle::writeMeta(const QString &metaTag, KoXmlWriter *writer) { if (m_metadata.contains(metaTag)) { writer->startElement(metaTag.toUtf8()); writer->addTextNode(m_metadata[metaTag].toUtf8()); writer->endElement(); } } void KoResourceBundle::writeUserDefinedMeta(const QString &metaTag, KoXmlWriter *writer) { if (m_metadata.contains(metaTag)) { writer->startElement("meta:meta-userdefined"); writer->addAttribute("meta:name", metaTag); writer->addAttribute("meta:value", m_metadata[metaTag]); writer->endElement(); } } bool KoResourceBundle::readMetaData(KoStore *resourceStore) { if (resourceStore->open("meta.xml")) { KoXmlDocument doc; if (!doc.setContent(resourceStore->device())) { qWarning() << "Could not parse meta.xml for" << filename(); return false; } // First find the manifest:manifest node. KoXmlNode n = doc.firstChild(); for (; !n.isNull(); n = n.nextSibling()) { if (!n.isElement()) { continue; } if (n.toElement().tagName() == "meta:meta") { break; } } if (n.isNull()) { qWarning() << "Could not find manifest node for bundle" << filename(); return false; } const KoXmlElement metaElement = n.toElement(); for (n = metaElement.firstChild(); !n.isNull(); n = n.nextSibling()) { if (n.isElement()) { KoXmlElement e = n.toElement(); if (e.tagName() == "meta:meta-userdefined") { if (e.attribute("meta:name") == "tag") { m_bundletags << e.attribute("meta:value"); } else { m_metadata.insert(e.attribute("meta:name"), e.attribute("meta:value")); } } else { m_metadata.insert(e.tagName(), e.firstChild().toText().data()); } } } resourceStore->close(); return true; } return false; } void KoResourceBundle::saveMetadata(QScopedPointer &store) { QBuffer buf; store->open("meta.xml"); buf.open(QBuffer::WriteOnly); KoXmlWriter metaWriter(&buf); metaWriter.startDocument("office:document-meta"); metaWriter.startElement("meta:meta"); writeMeta(KisStoragePlugin::s_meta_generator, &metaWriter); metaWriter.startElement(KisStoragePlugin::s_meta_version.toUtf8()); metaWriter.addTextNode(m_bundleVersion.toUtf8()); metaWriter.endElement(); writeMeta(KisStoragePlugin::s_meta_author, &metaWriter); writeMeta(KisStoragePlugin::s_meta_title, &metaWriter); writeMeta(KisStoragePlugin::s_meta_description, &metaWriter); writeMeta(KisStoragePlugin::s_meta_initial_creator, &metaWriter); writeMeta(KisStoragePlugin::s_meta_creator, &metaWriter); writeMeta(KisStoragePlugin::s_meta_creation_date, &metaWriter); writeMeta(KisStoragePlugin::s_meta_dc_date, &metaWriter); writeUserDefinedMeta("email", &metaWriter); writeUserDefinedMeta("license", &metaWriter); writeUserDefinedMeta("website", &metaWriter); Q_FOREACH (const QString &tag, m_bundletags) { metaWriter.startElement(KisStoragePlugin::s_meta_user_defined.toUtf8()); metaWriter.addAttribute(KisStoragePlugin::s_meta_name.toUtf8(), "tag"); metaWriter.addAttribute(KisStoragePlugin::s_meta_value.toUtf8(), tag); metaWriter.endElement(); } metaWriter.endElement(); // meta:meta metaWriter.endDocument(); buf.close(); store->write(buf.data()); store->close(); } void KoResourceBundle::saveManifest(QScopedPointer &store) { store->open("META-INF/manifest.xml"); QBuffer buf; buf.open(QBuffer::WriteOnly); m_manifest.save(&buf); buf.close(); store->write(buf.data()); store->close(); } int KoResourceBundle::resourceCount() const { return m_manifest.files().count(); } KoResourceBundleManifest &KoResourceBundle::manifest() { return m_manifest; } KoResourceSP KoResourceBundle::resource(const QString &resourceType, const QString &filepath) { if (filename().isEmpty()) return 0; if (m_resourceCache.contains(filepath)) { return m_resourceCache[filepath]; } QScopedPointer resourceStore(KoStore::createStore(filename(), KoStore::Read, "application/x-krita-resourcebundle", KoStore::Zip)); if (!resourceStore || resourceStore->bad()) { qWarning() << "Could not open store on bundle" << filename(); return 0; } if (!resourceStore->open(filepath)) { qWarning() << "Could not open file in bundle" << filepath; } QString mime = KisMimeDatabase::mimeTypeForSuffix(filepath); KisResourceLoaderBase *loader = KisResourceLoaderRegistry::instance()->loader(resourceType, mime); if (!loader) { qWarning() << "Could not create loader for" << resourceType << filepath << mime; return 0; } KoResourceSP res = loader->load(filepath, *resourceStore->device()); resourceStore->close(); m_resourceCache[filepath] = res; return res; } diff --git a/libs/ui/KisApplication.cpp b/libs/ui/KisApplication.cpp index 843a75fa7e..4dc73e4cfd 100644 --- a/libs/ui/KisApplication.cpp +++ b/libs/ui/KisApplication.cpp @@ -1,889 +1,889 @@ /* * Copyright (C) 1998, 1999 Torben Weis * Copyright (C) 2012 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KisApplication.h" #include #ifdef Q_OS_WIN #include #include #endif #ifdef Q_OS_OSX #include "osx.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KoConfig.h" #include #include #include #include "thememanager.h" #include "KisPrintJob.h" #include "KisDocument.h" #include "KisMainWindow.h" #include "KisAutoSaveRecoveryDialog.h" #include "KisPart.h" #include #include "kis_md5_generator.h" #include "kis_splash_screen.h" #include "kis_config.h" #include "flake/kis_shape_selection.h" #include #include #include #include #include #include #include #include "kisexiv2/kis_exiv2.h" #include "KisApplicationArguments.h" #include #include "kis_action_registry.h" #include #include #include #include "kis_image_barrier_locker.h" #include "opengl/kis_opengl.h" #include "kis_spin_box_unit_manager.h" #include "kis_document_aware_spin_box_unit_manager.h" #include "KisViewManager.h" #include "kis_workspace_resource.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "widgets/KisScreenColorPicker.h" #include "KisDlgInternalColorSelector.h" namespace { const QTime appStartTime(QTime::currentTime()); } class KisApplication::Private { public: Private() {} QPointer splashScreen; KisAutoSaveRecoveryDialog *autosaveDialog {0}; QPointer mainWindow; // The first mainwindow we create on startup bool batchRun {false}; }; class KisApplication::ResetStarting { public: ResetStarting(KisSplashScreen *splash, int fileCount) : m_splash(splash) , m_fileCount(fileCount) { } ~ResetStarting() { if (m_splash) { m_splash->hide(); } } QPointer m_splash; int m_fileCount; }; KisApplication::KisApplication(const QString &key, int &argc, char **argv) : QtSingleApplication(key, argc, argv) , d(new Private) { #ifdef Q_OS_OSX setMouseCoalescingEnabled(false); #endif QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath()); setApplicationDisplayName("Krita"); setApplicationName("krita"); // Note: Qt docs suggest we set this, but if we do, we get resource paths of the form of krita/krita, which is weird. // setOrganizationName("krita"); setOrganizationDomain("krita.org"); QString version = KritaVersionWrapper::versionString(true); setApplicationVersion(version); setWindowIcon(KisIconUtils::loadIcon("calligrakrita")); if (qgetenv("KRITA_NO_STYLE_OVERRIDE").isEmpty()) { QStringList styles = QStringList() << "breeze" << "fusion" << "plastique"; if (!styles.contains(style()->objectName().toLower())) { Q_FOREACH (const QString & style, styles) { if (!setStyle(style)) { qDebug() << "No" << style << "available."; } else { qDebug() << "Set style" << style; break; } } } } else { qDebug() << "Style override disabled, using" << style()->objectName(); } KisOpenGL::initialize(); } #if defined(Q_OS_WIN) && defined(ENV32BIT) typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); LPFN_ISWOW64PROCESS fnIsWow64Process; BOOL isWow64() { BOOL bIsWow64 = FALSE; //IsWow64Process is not available on all supported versions of Windows. //Use GetModuleHandle to get a handle to the DLL that contains the function //and GetProcAddress to get a pointer to the function if available. fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress( GetModuleHandle(TEXT("kernel32")),"IsWow64Process"); if(0 != fnIsWow64Process) { if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64)) { //handle error } } return bIsWow64; } #endif void KisApplication::initializeGlobals(const KisApplicationArguments &args) { int dpiX = args.dpiX(); int dpiY = args.dpiY(); if (dpiX > 0 && dpiY > 0) { KoDpi::setDPI(dpiX, dpiY); } } void KisApplication::addResourceTypes() { // qDebug() << "addResourceTypes();"; // All Krita's resource types KoResourcePaths::addResourceType("markers", "data", "/styles/"); KoResourcePaths::addResourceType("kis_pics", "data", "/pics/"); KoResourcePaths::addResourceType("kis_images", "data", "/images/"); KoResourcePaths::addResourceType("metadata_schema", "data", "/metadata/schemas/"); KoResourcePaths::addResourceType("brushes", "data", "/brushes/"); KoResourcePaths::addResourceType("kis_taskset", "data", "/taskset/"); KoResourcePaths::addResourceType("kis_taskset", "data", "/taskset/"); KoResourcePaths::addResourceType("gmic_definitions", "data", "/gmic/"); KoResourcePaths::addResourceType("kis_resourcebundles", "data", "/bundles/"); KoResourcePaths::addResourceType("kis_defaultpresets", "data", "/defaultpresets/"); KoResourcePaths::addResourceType("paintoppresets", "data", "/paintoppresets/"); KoResourcePaths::addResourceType("workspaces", "data", "/workspaces/"); KoResourcePaths::addResourceType("windowlayouts", "data", "/windowlayouts/"); KoResourcePaths::addResourceType("sessions", "data", "/sessions/"); KoResourcePaths::addResourceType("psd_layer_style_collections", "data", "/asl"); KoResourcePaths::addResourceType("patterns", "data", "/patterns/", true); KoResourcePaths::addResourceType("gradients", "data", "/gradients/"); KoResourcePaths::addResourceType("gradients", "data", "/gradients/", true); KoResourcePaths::addResourceType("palettes", "data", "/palettes/", true); KoResourcePaths::addResourceType("kis_shortcuts", "data", "/shortcuts/"); KoResourcePaths::addResourceType("kis_actions", "data", "/actions"); KoResourcePaths::addResourceType("icc_profiles", "data", "/color/icc"); KoResourcePaths::addResourceType("icc_profiles", "data", "/profiles/"); KoResourcePaths::addResourceType("ko_effects", "data", "/effects/"); KoResourcePaths::addResourceType("tags", "data", "/tags/"); KoResourcePaths::addResourceType("templates", "data", "/templates"); KoResourcePaths::addResourceType("pythonscripts", "data", "/pykrita"); KoResourcePaths::addResourceType("symbols", "data", "/symbols"); KoResourcePaths::addResourceType("preset_icons", "data", "/preset_icons"); KoResourcePaths::addResourceType("gamutmasks", "data", "/gamutmasks/", true); // // Extra directories to look for create resources. (Does anyone actually use that anymore?) // KoResourcePaths::addResourceDir("gradients", "/usr/share/create/gradients/gimp"); // KoResourcePaths::addResourceDir("gradients", QDir::homePath() + QString("/.create/gradients/gimp")); // KoResourcePaths::addResourceDir("patterns", "/usr/share/create/patterns/gimp"); // KoResourcePaths::addResourceDir("patterns", QDir::homePath() + QString("/.create/patterns/gimp")); // KoResourcePaths::addResourceDir("brushes", "/usr/share/create/brushes/gimp"); // KoResourcePaths::addResourceDir("brushes", QDir::homePath() + QString("/.create/brushes/gimp")); // KoResourcePaths::addResourceDir("palettes", "/usr/share/create/swatches"); // KoResourcePaths::addResourceDir("palettes", QDir::homePath() + QString("/.create/swatches")); // Make directories for all resources we can save, and tags QDir d; d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/tags/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/asl/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/bundles/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/brushes/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/gradients/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/paintoppresets/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/palettes/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/patterns/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/taskset/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/workspaces/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/input/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/pykrita/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/symbols/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/color-schemes/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/preset_icons/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/preset_icons/tool_icons/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/preset_icons/emblem_icons/"); d.mkpath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/gamutmasks/"); } bool KisApplication::loadResources() { KisResourceLoaderRegistry *reg = KisResourceLoaderRegistry::instance(); reg->add(new KisResourceLoader("paintoppresets", "paintoppresets", QStringList() << "application/x-krita-paintoppreset")); reg->add(new KisResourceLoader("gbr_brushes", "brushes", QStringList() << "image/x-gimp-brush")); reg->add(new KisResourceLoader("gih_brushes", "brushes", QStringList() << "image/x-gimp-brush-animated")); reg->add(new KisResourceLoader("svg_brushes", "brushes", QStringList() << "image/svg+xml")); reg->add(new KisResourceLoader("png_brushes", "brushes", QStringList() << "image/png")); reg->add(new KisResourceLoader("segmented_gradients", "gradients", QStringList() << "application/x-gimp-gradient")); reg->add(new KisResourceLoader("stop_gradients", "gradients", QStringList() << "application/x-karbon-gradient" << "image/svg+xml")); reg->add(new KisResourceLoader("palettes", "palettes", QStringList() << KisMimeDatabase::mimeTypeForSuffix("kpl") << KisMimeDatabase::mimeTypeForSuffix("gpl") << KisMimeDatabase::mimeTypeForSuffix("pal") << KisMimeDatabase::mimeTypeForSuffix("act") << KisMimeDatabase::mimeTypeForSuffix("aco") << KisMimeDatabase::mimeTypeForSuffix("css") << KisMimeDatabase::mimeTypeForSuffix("colors") << KisMimeDatabase::mimeTypeForSuffix("xml") << KisMimeDatabase::mimeTypeForSuffix("sbz"))); QList src = QImageReader::supportedMimeTypes(); QStringList allImageMimes; Q_FOREACH(const QByteArray ba, src) { allImageMimes << QString::fromUtf8(ba); } allImageMimes << KisMimeDatabase::mimeTypeForSuffix("pat"); reg->add(new KisResourceLoader("patterns", "patterns", allImageMimes)); reg->add(new KisResourceLoader("workspaces", "workspaces", QStringList() << "application/x-krita-workspace")); reg->add(new KisResourceLoader("symbols", "symbols", QStringList() << "image/svg+xml")); reg->add(new KisResourceLoader("windowlayouts", "sessions", QStringList() << "application/x-krita-windowlayout")); reg->add(new KisResourceLoader("sessions", "sessions", QStringList() << "application/x-krita-session")); reg->add(new KisResourceLoader("gamutmasks", "gamutmasks", QStringList() << "application/x-krita-gamutmask")); if (!KisResourceCacheDb::initialize(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation))) { QMessageBox::critical(0, i18nc("@title:window", "Krita: Fatal error"), i18n("Could not create the resources cache database. Krita will quit now.")); return false; } KisResourceLocator::LocatorError r = KisResourceLocator::instance()->initialize(KoResourcePaths::getApplicationRoot() + "/share/krita"); connect(KisResourceLocator::instance(), SIGNAL(progressMessage(const QString&)), this, SLOT(setSplashScreenLoadingText(const QString&))); if (r != KisResourceLocator::LocatorError::Ok ) { QMessageBox::critical(0, i18nc("@title:window", "Krita: Fatal error"), KisResourceLocator::instance()->errorMessages().join('\n') + i18n("\n\nKrita will quit now.")); return false; } setSplashScreenLoadingText(i18n("Loading Resources...")); processEvents(); KoResourceServerProvider::instance(); setSplashScreenLoadingText(i18n("Loading Brush Presets...")); processEvents(); KisResourceServerProvider::instance(); setSplashScreenLoadingText(i18n("Loading Brushes...")); processEvents(); KisBrushServer::instance()->brushServer(); setSplashScreenLoadingText(i18n("Loading Bundles...")); processEvents(); KisResourceBundleServerProvider::instance(); return true; } void KisApplication::loadResourceTags() { // qDebug() << "loadResourceTags()"; KoResourceServerProvider::instance()->patternServer()->loadTags(); KoResourceServerProvider::instance()->gradientServer()->loadTags(); KoResourceServerProvider::instance()->paletteServer()->loadTags(); KoResourceServerProvider::instance()->svgSymbolCollectionServer()->loadTags(); KisBrushServer::instance()->brushServer()->loadTags(); KisResourceServerProvider::instance()->workspaceServer()->loadTags(); KisResourceServerProvider::instance()->layerStyleCollectionServer()->loadTags(); KisResourceBundleServerProvider::instance()->resourceBundleServer()->loadTags(); KisResourceServerProvider::instance()->paintOpPresetServer()->loadTags(); KisResourceServerProvider::instance()->paintOpPresetServer()->clearOldSystemTags(); } void KisApplication::loadPlugins() { // qDebug() << "loadPlugins();"; KoShapeRegistry* r = KoShapeRegistry::instance(); r->add(new KisShapeSelectionFactory()); KisActionRegistry::instance(); KisFilterRegistry::instance(); KisGeneratorRegistry::instance(); KisPaintOpRegistry::instance(); KoColorSpaceRegistry::instance(); } void KisApplication::loadGuiPlugins() { // qDebug() << "loadGuiPlugins();"; // Load the krita-specific tools setSplashScreenLoadingText(i18n("Loading Plugins for Krita/Tool...")); processEvents(); // qDebug() << "loading tools"; KoPluginLoader::instance()->load(QString::fromLatin1("Krita/Tool"), QString::fromLatin1("[X-Krita-Version] == 28")); // Load dockers setSplashScreenLoadingText(i18n("Loading Plugins for Krita/Dock...")); processEvents(); // qDebug() << "loading dockers"; KoPluginLoader::instance()->load(QString::fromLatin1("Krita/Dock"), QString::fromLatin1("[X-Krita-Version] == 28")); // XXX_EXIV: make the exiv io backends real plugins setSplashScreenLoadingText(i18n("Loading Plugins Exiv/IO...")); processEvents(); // qDebug() << "loading exiv2"; KisExiv2::initialize(); } bool KisApplication::start(const KisApplicationArguments &args) { KisConfig cfg(false); #if defined(Q_OS_WIN) #ifdef ENV32BIT if (isWow64() && !cfg.readEntry("WarnedAbout32Bits", false)) { QMessageBox::information(0, i18nc("@title:window", "Krita: Warning"), i18n("You are running a 32 bits build on a 64 bits Windows.\n" "This is not recommended.\n" "Please download and install the x64 build instead.")); cfg.writeEntry("WarnedAbout32Bits", true); } #endif #endif QString opengl = cfg.canvasState(); if (opengl == "OPENGL_NOT_TRIED" ) { cfg.setCanvasState("TRY_OPENGL"); } else if (opengl != "OPENGL_SUCCESS") { cfg.setCanvasState("OPENGL_FAILED"); } setSplashScreenLoadingText(i18n("Initializing Globals")); processEvents(); initializeGlobals(args); const bool doNewImage = args.doNewImage(); const bool doTemplate = args.doTemplate(); const bool exportAs = args.exportAs(); const QString exportFileName = args.exportFileName(); d->batchRun = (exportAs || !exportFileName.isEmpty()); const bool needsMainWindow = !exportAs; // only show the mainWindow when no command-line mode option is passed bool showmainWindow = !exportAs; // would be !batchRun; const bool showSplashScreen = !d->batchRun && qEnvironmentVariableIsEmpty("NOSPLASH"); if (showSplashScreen && d->splashScreen) { d->splashScreen->show(); d->splashScreen->repaint(); processEvents(); } KoHashGeneratorProvider::instance()->setGenerator("MD5", new KisMD5Generator()); KConfigGroup group(KSharedConfig::openConfig(), "theme"); Digikam::ThemeManager themeManager; themeManager.setCurrentTheme(group.readEntry("Theme", "Krita dark")); ResetStarting resetStarting(d->splashScreen, args.filenames().count()); // remove the splash when done Q_UNUSED(resetStarting); // Make sure we can save resources and tags setSplashScreenLoadingText(i18n("Adding resource types")); processEvents(); addResourceTypes(); // Load the plugins loadPlugins(); // Load all resources if (!loadResources()) { return false; } // Load all the tags loadResourceTags(); // Load the gui plugins loadGuiPlugins(); KisPart *kisPart = KisPart::instance(); if (needsMainWindow) { // show a mainWindow asap, if we want that setSplashScreenLoadingText(i18n("Loading Main Window...")); processEvents(); bool sessionNeeded = true; auto sessionMode = cfg.sessionOnStartup(); if (!args.session().isEmpty()) { sessionNeeded = !kisPart->restoreSession(args.session()); } else if (sessionMode == KisConfig::SOS_ShowSessionManager) { showmainWindow = false; sessionNeeded = false; kisPart->showSessionManager(); } else if (sessionMode == KisConfig::SOS_PreviousSession) { KConfigGroup sessionCfg = KSharedConfig::openConfig()->group("session"); const QString &sessionName = sessionCfg.readEntry("previousSession"); sessionNeeded = !kisPart->restoreSession(sessionName); } if (sessionNeeded) { kisPart->startBlankSession(); } if (!args.windowLayout().isEmpty()) { KoResourceServer * rserver = KisResourceServerProvider::instance()->windowLayoutServer(); - KisWindowLayoutResource* windowLayout = rserver->resourceByName(args.windowLayout()); + KisWindowLayoutResourceSP windowLayout = rserver->resourceByName(args.windowLayout()); if (windowLayout) { windowLayout->applyLayout(); } } if (showmainWindow) { d->mainWindow = kisPart->currentMainwindow(); if (!args.workspace().isEmpty()) { KoResourceServer * rserver = KisResourceServerProvider::instance()->workspaceServer(); - KisWorkspaceResource* workspace = rserver->resourceByName(args.workspace()); + KisWorkspaceResourceSP workspace = rserver->resourceByName(args.workspace()); if (workspace) { d->mainWindow->restoreWorkspace(workspace); } } if (args.canvasOnly()) { d->mainWindow->viewManager()->switchCanvasOnly(true); } if (args.fullScreen()) { d->mainWindow->showFullScreen(); } } else { d->mainWindow = kisPart->createMainWindow(); } } short int numberOfOpenDocuments = 0; // number of documents open // Check for autosave files that can be restored, if we're not running a batchrun (test) if (!d->batchRun) { checkAutosaveFiles(); } setSplashScreenLoadingText(QString()); // done loading, so clear out label processEvents(); //configure the unit manager KisSpinBoxUnitManagerFactory::setDefaultUnitManagerBuilder(new KisDocumentAwareSpinBoxUnitManagerBuilder()); connect(this, &KisApplication::aboutToQuit, &KisSpinBoxUnitManagerFactory::clearUnitManagerBuilder); //ensure the builder is destroyed when the application leave. //the new syntax slot syntax allow to connect to a non q_object static method. // Create a new image, if needed if (doNewImage) { KisDocument *doc = args.image(); if (doc) { kisPart->addDocument(doc); d->mainWindow->addViewAndNotifyLoadingCompleted(doc); } } // Get the command line arguments which we have to parse int argsCount = args.filenames().count(); if (argsCount > 0) { // Loop through arguments for (int argNumber = 0; argNumber < argsCount; argNumber++) { QString fileName = args.filenames().at(argNumber); // are we just trying to open a template? if (doTemplate) { // called in mix with batch options? ignore and silently skip if (d->batchRun) { continue; } if (createNewDocFromTemplate(fileName, d->mainWindow)) { ++numberOfOpenDocuments; } // now try to load } else { if (exportAs) { QString outputMimetype = KisMimeDatabase::mimeTypeForFile(exportFileName, false); if (outputMimetype == "application/octetstream") { dbgKrita << i18n("Mimetype not found, try using the -mimetype option") << endl; return 1; } KisDocument *doc = kisPart->createDocument(); doc->setFileBatchMode(d->batchRun); doc->openUrl(QUrl::fromLocalFile(fileName)); qApp->processEvents(); // For vector layers to be updated doc->setFileBatchMode(true); if (!doc->exportDocumentSync(QUrl::fromLocalFile(exportFileName), outputMimetype.toLatin1())) { dbgKrita << "Could not export " << fileName << "to" << exportFileName << ":" << doc->errorMessage(); } QTimer::singleShot(0, this, SLOT(quit())); } else if (d->mainWindow) { if (fileName.endsWith(".bundle")) { d->mainWindow->installBundle(fileName); } else { KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; if (d->mainWindow->openDocument(QUrl::fromLocalFile(fileName), flags)) { // Normal case, success numberOfOpenDocuments++; } } } } } } // fixes BUG:369308 - Krita crashing on splash screen when loading. // trying to open a file before Krita has loaded can cause it to hang and crash if (d->splashScreen) { d->splashScreen->displayLinks(true); d->splashScreen->displayRecentFiles(true); } // not calling this before since the program will quit there. return true; } KisApplication::~KisApplication() { } void KisApplication::setSplashScreen(QWidget *splashScreen) { d->splashScreen = qobject_cast(splashScreen); } void KisApplication::setSplashScreenLoadingText(const QString &textToLoad) { if (d->splashScreen) { d->splashScreen->setLoadingText(textToLoad); d->splashScreen->repaint(); } } void KisApplication::hideSplashScreen() { if (d->splashScreen) { // hide the splashscreen to see the dialog d->splashScreen->hide(); } } bool KisApplication::notify(QObject *receiver, QEvent *event) { try { return QApplication::notify(receiver, event); } catch (std::exception &e) { qWarning("Error %s sending event %i to object %s", e.what(), event->type(), qPrintable(receiver->objectName())); } catch (...) { qWarning("Error sending event %i to object %s", event->type(), qPrintable(receiver->objectName())); } return false; } void KisApplication::remoteArguments(QByteArray message, QObject *socket) { Q_UNUSED(socket); // check if we have any mainwindow KisMainWindow *mw = qobject_cast(qApp->activeWindow()); if (!mw) { mw = KisPart::instance()->mainWindows().first(); } if (!mw) { return; } KisApplicationArguments args = KisApplicationArguments::deserialize(message); const bool doTemplate = args.doTemplate(); const int argsCount = args.filenames().count(); if (argsCount > 0) { // Loop through arguments for (int argNumber = 0; argNumber < argsCount; ++argNumber) { QString filename = args.filenames().at(argNumber); // are we just trying to open a template? if (doTemplate) { createNewDocFromTemplate(filename, mw); } else if (QFile(filename).exists()) { KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; mw->openDocument(QUrl::fromLocalFile(filename), flags); } } } } void KisApplication::fileOpenRequested(const QString &url) { KisMainWindow *mainWindow = KisPart::instance()->mainWindows().first(); if (mainWindow) { KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; mainWindow->openDocument(QUrl::fromLocalFile(url), flags); } } void KisApplication::checkAutosaveFiles() { if (d->batchRun) return; // Check for autosave files from a previous run. There can be several, and // we want to offer a restore for every one. Including a nice thumbnail! QStringList filters; filters << QString(".krita-*-*-autosave.kra"); #ifdef Q_OS_WIN QDir dir = QDir::temp(); #else QDir dir = QDir::home(); #endif // all autosave files for our application QStringList autosaveFiles = dir.entryList(filters, QDir::Files | QDir::Hidden); // Allow the user to make their selection if (autosaveFiles.size() > 0) { if (d->splashScreen) { // hide the splashscreen to see the dialog d->splashScreen->hide(); } d->autosaveDialog = new KisAutoSaveRecoveryDialog(autosaveFiles, activeWindow()); QDialog::DialogCode result = (QDialog::DialogCode) d->autosaveDialog->exec(); if (result == QDialog::Accepted) { QStringList filesToRecover = d->autosaveDialog->recoverableFiles(); Q_FOREACH (const QString &autosaveFile, autosaveFiles) { if (!filesToRecover.contains(autosaveFile)) { QFile::remove(dir.absolutePath() + "/" + autosaveFile); } } autosaveFiles = filesToRecover; } else { autosaveFiles.clear(); } if (autosaveFiles.size() > 0) { QList autosaveUrls; Q_FOREACH (const QString &autoSaveFile, autosaveFiles) { const QUrl url = QUrl::fromLocalFile(dir.absolutePath() + QLatin1Char('/') + autoSaveFile); autosaveUrls << url; } if (d->mainWindow) { Q_FOREACH (const QUrl &url, autosaveUrls) { KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; d->mainWindow->openDocument(url, flags | KisMainWindow::RecoveryFile); } } } // cleanup delete d->autosaveDialog; d->autosaveDialog = nullptr; } } bool KisApplication::createNewDocFromTemplate(const QString &fileName, KisMainWindow *mainWindow) { QString templatePath; const QUrl templateUrl = QUrl::fromLocalFile(fileName); if (QFile::exists(fileName)) { templatePath = templateUrl.toLocalFile(); dbgUI << "using full path..."; } else { QString desktopName(fileName); const QString templatesResourcePath = QStringLiteral("templates/"); QStringList paths = KoResourcePaths::findAllResources("data", templatesResourcePath + "*/" + desktopName); if (paths.isEmpty()) { paths = KoResourcePaths::findAllResources("data", templatesResourcePath + desktopName); } if (paths.isEmpty()) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("No template found for: %1", desktopName)); } else if (paths.count() > 1) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Too many templates found for: %1", desktopName)); } else { templatePath = paths.at(0); } } if (!templatePath.isEmpty()) { QUrl templateBase; templateBase.setPath(templatePath); KDesktopFile templateInfo(templatePath); QString templateName = templateInfo.readUrl(); QUrl templateURL; templateURL.setPath(templateBase.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path() + '/' + templateName); KisMainWindow::OpenFlags batchFlags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None; if (mainWindow->openDocument(templateURL, KisMainWindow::Import | batchFlags)) { dbgUI << "Template loaded..."; return true; } else { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Template %1 failed to load.", templateURL.toDisplayString())); } } return false; } void KisApplication::clearConfig() { KIS_ASSERT_RECOVER_RETURN(qApp->thread() == QThread::currentThread()); KSharedConfigPtr config = KSharedConfig::openConfig(); // find user settings file bool createDir = false; QString kritarcPath = KoResourcePaths::locateLocal("config", "kritarc", createDir); QFile configFile(kritarcPath); if (configFile.exists()) { // clear file if (configFile.open(QFile::WriteOnly)) { configFile.close(); } else { QMessageBox::warning(0, i18nc("@title:window", "Krita"), i18n("Failed to clear %1\n\n" "Please make sure no other program is using the file and try again.", kritarcPath), QMessageBox::Ok, QMessageBox::Ok); } } // reload from disk; with the user file settings cleared, // this should load any default configuration files shipping with the program config->reparseConfiguration(); config->sync(); } void KisApplication::askClearConfig() { Qt::KeyboardModifiers mods = QApplication::queryKeyboardModifiers(); bool askClearConfig = (mods & Qt::ControlModifier) && (mods & Qt::ShiftModifier) && (mods & Qt::AltModifier); if (askClearConfig) { bool ok = QMessageBox::question(0, i18nc("@title:window", "Krita"), i18n("Do you want to clear the settings file?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes; if (ok) { clearConfig(); } } } diff --git a/libs/ui/KisDocument.cpp b/libs/ui/KisDocument.cpp index 8194b78337..ee4368393b 100644 --- a/libs/ui/KisDocument.cpp +++ b/libs/ui/KisDocument.cpp @@ -1,1855 +1,1855 @@ /* This file is part of the Krita project * * Copyright (C) 2014 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KisMainWindow.h" // XXX: remove #include // XXX: remove #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Krita Image #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_layer_utils.h" // Local #include "KisViewManager.h" #include "kis_clipboard.h" #include "widgets/kis_custom_image_widget.h" #include "canvas/kis_canvas2.h" #include "flake/kis_shape_controller.h" #include "kis_statusbar.h" #include "widgets/kis_progress_widget.h" #include "kis_canvas_resource_provider.h" #include "KisResourceServerProvider.h" #include "kis_node_manager.h" #include "KisPart.h" #include "KisApplication.h" #include "KisDocument.h" #include "KisImportExportManager.h" #include "KisView.h" #include "kis_grid_config.h" #include "kis_guides_config.h" #include "kis_image_barrier_lock_adapter.h" #include "KisReferenceImagesLayer.h" #include #include "kis_config_notifier.h" #include "kis_async_action_feedback.h" #include "KisCloneDocumentStroke.h" // Define the protocol used here for embedded documents' URL // This used to "store" but QUrl didn't like it, // so let's simply make it "tar" ! #define STORE_PROTOCOL "tar" // The internal path is a hack to make QUrl happy and for document children #define INTERNAL_PROTOCOL "intern" #define INTERNAL_PREFIX "intern:/" // Warning, keep it sync in koStore.cc #include using namespace std; namespace { constexpr int errorMessageTimeout = 5000; constexpr int successMessageTimeout = 1000; } /********************************************************** * * KisDocument * **********************************************************/ //static QString KisDocument::newObjectName() { static int s_docIFNumber = 0; QString name; name.setNum(s_docIFNumber++); name.prepend("document_"); return name; } class UndoStack : public KUndo2Stack { public: UndoStack(KisDocument *doc) : KUndo2Stack(doc), m_doc(doc) { } void setIndex(int idx) override { KisImageWSP image = this->image(); image->requestStrokeCancellation(); if(image->tryBarrierLock()) { KUndo2Stack::setIndex(idx); image->unlock(); } } void notifySetIndexChangedOneCommand() override { KisImageWSP image = this->image(); image->unlock(); /** * Some very weird commands may emit blocking signals to * the GUI (e.g. KisGuiContextCommand). Here is the best thing * we can do to avoid the deadlock */ while(!image->tryBarrierLock()) { QApplication::processEvents(); } } void undo() override { KisImageWSP image = this->image(); image->requestUndoDuringStroke(); if (image->tryUndoUnfinishedLod0Stroke() == UNDO_OK) { return; } if(image->tryBarrierLock()) { KUndo2Stack::undo(); image->unlock(); } } void redo() override { KisImageWSP image = this->image(); if(image->tryBarrierLock()) { KUndo2Stack::redo(); image->unlock(); } } private: KisImageWSP image() { KisImageWSP currentImage = m_doc->image(); Q_ASSERT(currentImage); return currentImage; } private: KisDocument *m_doc; }; class Q_DECL_HIDDEN KisDocument::Private { public: Private(KisDocument *q) : docInfo(new KoDocumentInfo(q)) // deleted by QObject , importExportManager(new KisImportExportManager(q)) // deleted manually , autoSaveTimer(new QTimer(q)) , undoStack(new UndoStack(q)) // deleted by QObject , m_bAutoDetectedMime(false) , modified(false) , readwrite(true) , firstMod(QDateTime::currentDateTime()) , lastMod(firstMod) , nserver(new KisNameServer(1)) , imageIdleWatcher(2000 /*ms*/) , globalAssistantsColor(KisConfig(true).defaultAssistantsColor()) , savingLock(&savingMutex) , batchMode(false) { if (QLocale().measurementSystem() == QLocale::ImperialSystem) { unit = KoUnit::Inch; } else { unit = KoUnit::Centimeter; } } Private(const Private &rhs, KisDocument *q) : docInfo(new KoDocumentInfo(*rhs.docInfo, q)) , unit(rhs.unit) , importExportManager(new KisImportExportManager(q)) , mimeType(rhs.mimeType) , outputMimeType(rhs.outputMimeType) , autoSaveTimer(new QTimer(q)) , undoStack(new UndoStack(q)) , guidesConfig(rhs.guidesConfig) , m_bAutoDetectedMime(rhs.m_bAutoDetectedMime) , m_url(rhs.m_url) , m_file(rhs.m_file) , modified(rhs.modified) , readwrite(rhs.readwrite) , firstMod(rhs.firstMod) , lastMod(rhs.lastMod) , nserver(new KisNameServer(*rhs.nserver)) , preActivatedNode(0) // the node is from another hierarchy! , imageIdleWatcher(2000 /*ms*/) , assistants(rhs.assistants) // WARNING: assistants should not store pointers to the document! , globalAssistantsColor(rhs.globalAssistantsColor) , paletteList(rhs.paletteList) , gridConfig(rhs.gridConfig) , savingLock(&savingMutex) , batchMode(rhs.batchMode) { // TODO: clone assistants } ~Private() { // Don't delete m_d->shapeController because it's in a QObject hierarchy. delete nserver; } KoDocumentInfo *docInfo = 0; KoUnit unit; KisImportExportManager *importExportManager = 0; // The filter-manager to use when loading/saving [for the options] QByteArray mimeType; // The actual mimetype of the document QByteArray outputMimeType; // The mimetype to use when saving QTimer *autoSaveTimer; QString lastErrorMessage; // see openFile() QString lastWarningMessage; int autoSaveDelay = 300; // in seconds, 0 to disable. bool modifiedAfterAutosave = false; bool isAutosaving = false; bool disregardAutosaveFailure = false; int autoSaveFailureCount = 0; KUndo2Stack *undoStack = 0; KisGuidesConfig guidesConfig; bool m_bAutoDetectedMime = false; // whether the mimetype in the arguments was detected by the part itself QUrl m_url; // local url - the one displayed to the user. QString m_file; // Local file - the only one the part implementation should deal with. QMutex savingMutex; bool modified = false; bool readwrite = false; QDateTime firstMod; QDateTime lastMod; KisNameServer *nserver; KisImageSP image; KisImageSP savingImage; KisNodeWSP preActivatedNode; KisShapeController* shapeController = 0; KoShapeController* koShapeController = 0; KisIdleWatcher imageIdleWatcher; QScopedPointer imageIdleConnection; QList assistants; QColor globalAssistantsColor; KisSharedPtr referenceImagesLayer; - QList paletteList; + QList paletteList; KisGridConfig gridConfig; StdLockableWrapper savingLock; bool modifiedWhileSaving = false; QScopedPointer backgroundSaveDocument; QPointer savingUpdater; QFuture childSavingFuture; KritaUtils::ExportFileJob backgroundSaveJob; bool isRecovered = false; bool batchMode { false }; void setImageAndInitIdleWatcher(KisImageSP _image) { image = _image; imageIdleWatcher.setTrackedImage(image); if (image) { imageIdleConnection.reset( new KisSignalAutoConnection( &imageIdleWatcher, SIGNAL(startedIdleMode()), image.data(), SLOT(explicitRegenerateLevelOfDetail()))); } } class StrippedSafeSavingLocker; }; class KisDocument::Private::StrippedSafeSavingLocker { public: StrippedSafeSavingLocker(QMutex *savingMutex, KisImageSP image) : m_locked(false) , m_image(image) , m_savingLock(savingMutex) , m_imageLock(image, true) { /** * Initial try to lock both objects. Locking the image guards * us from any image composition threads running in the * background, while savingMutex guards us from entering the * saving code twice by autosave and main threads. * * Since we are trying to lock multiple objects, so we should * do it in a safe manner. */ m_locked = std::try_lock(m_imageLock, m_savingLock) < 0; if (!m_locked) { m_image->requestStrokeEnd(); QApplication::processEvents(); // one more try... m_locked = std::try_lock(m_imageLock, m_savingLock) < 0; } } ~StrippedSafeSavingLocker() { if (m_locked) { m_imageLock.unlock(); m_savingLock.unlock(); } } bool successfullyLocked() const { return m_locked; } private: bool m_locked; KisImageSP m_image; StdLockableWrapper m_savingLock; KisImageBarrierLockAdapter m_imageLock; }; KisDocument::KisDocument() : d(new Private(this)) { connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged())); connect(d->undoStack, SIGNAL(cleanChanged(bool)), this, SLOT(slotUndoStackCleanChanged(bool))); connect(d->autoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave())); setObjectName(newObjectName()); // preload the krita resources KisResourceServerProvider::instance(); d->shapeController = new KisShapeController(this, d->nserver), d->koShapeController = new KoShapeController(0, d->shapeController), slotConfigChanged(); } KisDocument::KisDocument(const KisDocument &rhs) : QObject(), d(new Private(*rhs.d, this)) { connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged())); connect(d->undoStack, SIGNAL(cleanChanged(bool)), this, SLOT(slotUndoStackCleanChanged(bool))); connect(d->autoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave())); setObjectName(rhs.objectName()); d->shapeController = new KisShapeController(this, d->nserver), d->koShapeController = new KoShapeController(0, d->shapeController), slotConfigChanged(); // clone the image with keeping the GUIDs of the layers intact // NOTE: we expect the image to be locked! setCurrentImage(rhs.image()->clone(true), false); if (rhs.d->preActivatedNode) { // since we clone uuid's, we can use them for lacating new // nodes. Otherwise we would need to use findSymmetricClone() d->preActivatedNode = KisLayerUtils::findNodeByUuid(d->image->root(), rhs.d->preActivatedNode->uuid()); } } KisDocument::~KisDocument() { // wait until all the pending operations are in progress waitForSavingToComplete(); /** * Push a timebomb, which will try to release the memory after * the document has been deleted */ KisPaintDevice::createMemoryReleaseObject()->deleteLater(); d->autoSaveTimer->disconnect(this); d->autoSaveTimer->stop(); delete d->importExportManager; // Despite being QObject they needs to be deleted before the image delete d->shapeController; delete d->koShapeController; if (d->image) { d->image->notifyAboutToBeDeleted(); /** * WARNING: We should wait for all the internal image jobs to * finish before entering KisImage's destructor. The problem is, * while execution of KisImage::~KisImage, all the weak shared * pointers pointing to the image enter an inconsistent * state(!). The shared counter is already zero and destruction * has started, but the weak reference doesn't know about it, * because KisShared::~KisShared hasn't been executed yet. So all * the threads running in background and having weak pointers will * enter the KisImage's destructor as well. */ d->image->requestStrokeCancellation(); d->image->waitForDone(); // clear undo commands that can still point to the image d->undoStack->clear(); d->image->waitForDone(); KisImageWSP sanityCheckPointer = d->image; Q_UNUSED(sanityCheckPointer); // The following line trigger the deletion of the image d->image.clear(); // check if the image has actually been deleted KIS_SAFE_ASSERT_RECOVER_NOOP(!sanityCheckPointer.isValid()); } delete d; } bool KisDocument::reload() { // XXX: reimplement! return false; } KisDocument *KisDocument::clone() { return new KisDocument(*this); } bool KisDocument::exportDocumentImpl(const KritaUtils::ExportFileJob &job, KisPropertiesConfigurationSP exportConfiguration) { QFileInfo filePathInfo(job.filePath); if (filePathInfo.exists() && !filePathInfo.isWritable()) { slotCompleteSavingDocument(job, KisImportExportFilter::CreationError, i18n("%1 cannot be written to. Please save under a different name.", job.filePath)); return false; } KisConfig cfg(true); if (cfg.backupFile() && filePathInfo.exists()) { KBackup::backupFile(job.filePath); } KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!job.mimeType.isEmpty(), false); const QString actionName = job.flags & KritaUtils::SaveIsExporting ? i18n("Exporting Document...") : i18n("Saving Document..."); bool started = initiateSavingInBackground(actionName, this, SLOT(slotCompleteSavingDocument(KritaUtils::ExportFileJob,KisImportExportFilter::ConversionStatus,QString)), job, exportConfiguration); if (!started) { emit canceled(QString()); } return started; } bool KisDocument::exportDocument(const QUrl &url, const QByteArray &mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration) { using namespace KritaUtils; SaveFlags flags = SaveIsExporting; if (showWarnings) { flags |= SaveShowWarnings; } return exportDocumentImpl(KritaUtils::ExportFileJob(url.toLocalFile(), mimeType, flags), exportConfiguration); } bool KisDocument::saveAs(const QUrl &url, const QByteArray &mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration) { using namespace KritaUtils; return exportDocumentImpl(ExportFileJob(url.toLocalFile(), mimeType, showWarnings ? SaveShowWarnings : SaveNone), exportConfiguration); } bool KisDocument::save(bool showWarnings, KisPropertiesConfigurationSP exportConfiguration) { return saveAs(url(), mimeType(), showWarnings, exportConfiguration); } QByteArray KisDocument::serializeToNativeByteArray() { QByteArray byteArray; QBuffer buffer(&byteArray); QScopedPointer filter(KisImportExportManager::filterForMimeType(nativeFormatMimeType(), KisImportExportManager::Export)); filter->setBatchMode(true); filter->setMimeType(nativeFormatMimeType()); Private::StrippedSafeSavingLocker locker(&d->savingMutex, d->image); if (!locker.successfullyLocked()) { return byteArray; } d->savingImage = d->image; if (filter->convert(this, &buffer) != KisImportExportFilter::OK) { qWarning() << "serializeToByteArray():: Could not export to our native format"; } return byteArray; } void KisDocument::slotCompleteSavingDocument(const KritaUtils::ExportFileJob &job, KisImportExportFilter::ConversionStatus status, const QString &errorMessage) { if (status == KisImportExportFilter::UserCancelled) return; const QString fileName = QFileInfo(job.filePath).fileName(); if (status != KisImportExportFilter::OK) { emit statusBarMessage(i18nc("%1 --- failing file name, %2 --- error message", "Error during saving %1: %2", fileName, exportErrorToUserMessage(status, errorMessage)), errorMessageTimeout); if (!fileBatchMode()) { const QString filePath = job.filePath; QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not save %1\nReason: %2", filePath, exportErrorToUserMessage(status, errorMessage))); } } else { if (!(job.flags & KritaUtils::SaveIsExporting)) { const QString existingAutoSaveBaseName = localFilePath(); const bool wasRecovered = isRecovered(); setUrl(QUrl::fromLocalFile(job.filePath)); setLocalFilePath(job.filePath); setMimeType(job.mimeType); updateEditingTime(true); if (!d->modifiedWhileSaving) { /** * If undo stack is already clean/empty, it doesn't emit any * signals, so we might forget update document modified state * (which was set, e.g. while recovering an autosave file) */ if (d->undoStack->isClean()) { setModified(false); } else { d->undoStack->setClean(); } } setRecovered(false); removeAutoSaveFiles(existingAutoSaveBaseName, wasRecovered); } emit completed(); emit sigSavingFinished(); emit statusBarMessage(i18n("Finished saving %1", fileName), successMessageTimeout); } } QByteArray KisDocument::mimeType() const { return d->mimeType; } void KisDocument::setMimeType(const QByteArray & mimeType) { d->mimeType = mimeType; } bool KisDocument::fileBatchMode() const { return d->batchMode; } void KisDocument::setFileBatchMode(const bool batchMode) { d->batchMode = batchMode; } KisDocument* KisDocument::lockAndCloneForSaving() { // force update of all the asynchronous nodes before cloning QApplication::processEvents(); KisLayerUtils::forceAllDelayedNodesUpdate(d->image->root()); KisMainWindow *window = KisPart::instance()->currentMainwindow(); if (window) { if (window->viewManager()) { if (!window->viewManager()->blockUntilOperationsFinished(d->image)) { return 0; } } } Private::StrippedSafeSavingLocker locker(&d->savingMutex, d->image); if (!locker.successfullyLocked()) { return 0; } return new KisDocument(*this); } bool KisDocument::exportDocumentSync(const QUrl &url, const QByteArray &mimeType, KisPropertiesConfigurationSP exportConfiguration) { Private::StrippedSafeSavingLocker locker(&d->savingMutex, d->image); if (!locker.successfullyLocked()) { return false; } d->savingImage = d->image; const QString fileName = url.toLocalFile(); KisImportExportFilter::ConversionStatus status = d->importExportManager-> exportDocument(fileName, fileName, mimeType, false, exportConfiguration); d->savingImage = 0; return status == KisImportExportFilter::OK; } bool KisDocument::initiateSavingInBackground(const QString actionName, const QObject *receiverObject, const char *receiverMethod, const KritaUtils::ExportFileJob &job, KisPropertiesConfigurationSP exportConfiguration) { return initiateSavingInBackground(actionName, receiverObject, receiverMethod, job, exportConfiguration, std::unique_ptr()); } bool KisDocument::initiateSavingInBackground(const QString actionName, const QObject *receiverObject, const char *receiverMethod, const KritaUtils::ExportFileJob &job, KisPropertiesConfigurationSP exportConfiguration, std::unique_ptr &&optionalClonedDocument) { KIS_ASSERT_RECOVER_RETURN_VALUE(job.isValid(), false); QScopedPointer clonedDocument; if (!optionalClonedDocument) { clonedDocument.reset(lockAndCloneForSaving()); } else { clonedDocument.reset(optionalClonedDocument.release()); } // we block saving until the current saving is finished! if (!clonedDocument || !d->savingMutex.tryLock()) { return false; } KIS_ASSERT_RECOVER_RETURN_VALUE(!d->backgroundSaveDocument, false); KIS_ASSERT_RECOVER_RETURN_VALUE(!d->backgroundSaveJob.isValid(), false); d->backgroundSaveDocument.reset(clonedDocument.take()); d->backgroundSaveJob = job; d->modifiedWhileSaving = false; if (d->backgroundSaveJob.flags & KritaUtils::SaveInAutosaveMode) { d->backgroundSaveDocument->d->isAutosaving = true; } connect(d->backgroundSaveDocument.data(), SIGNAL(sigBackgroundSavingFinished(KisImportExportFilter::ConversionStatus,QString)), this, SLOT(slotChildCompletedSavingInBackground(KisImportExportFilter::ConversionStatus,QString))); connect(this, SIGNAL(sigCompleteBackgroundSaving(KritaUtils::ExportFileJob,KisImportExportFilter::ConversionStatus,QString)), receiverObject, receiverMethod, Qt::UniqueConnection); bool started = d->backgroundSaveDocument->startExportInBackground(actionName, job.filePath, job.filePath, job.mimeType, job.flags & KritaUtils::SaveShowWarnings, exportConfiguration); if (!started) { // the state should have been deinitialized in slotChildCompletedSavingInBackground() KIS_SAFE_ASSERT_RECOVER (!d->backgroundSaveDocument && !d->backgroundSaveJob.isValid()) { d->backgroundSaveDocument.take()->deleteLater(); d->savingMutex.unlock(); d->backgroundSaveJob = KritaUtils::ExportFileJob(); } } return started; } void KisDocument::slotChildCompletedSavingInBackground(KisImportExportFilter::ConversionStatus status, const QString &errorMessage) { KIS_SAFE_ASSERT_RECOVER(!d->savingMutex.tryLock()) { d->savingMutex.unlock(); return; } KIS_SAFE_ASSERT_RECOVER_RETURN(d->backgroundSaveDocument); if (d->backgroundSaveJob.flags & KritaUtils::SaveInAutosaveMode) { d->backgroundSaveDocument->d->isAutosaving = false; } d->backgroundSaveDocument.take()->deleteLater(); d->savingMutex.unlock(); KIS_SAFE_ASSERT_RECOVER_RETURN(d->backgroundSaveJob.isValid()); const KritaUtils::ExportFileJob job = d->backgroundSaveJob; d->backgroundSaveJob = KritaUtils::ExportFileJob(); emit sigCompleteBackgroundSaving(job, status, errorMessage); } void KisDocument::slotAutoSaveImpl(std::unique_ptr &&optionalClonedDocument) { if (!d->modified || !d->modifiedAfterAutosave) return; const QString autoSaveFileName = generateAutoSaveFileName(localFilePath()); emit statusBarMessage(i18n("Autosaving... %1", autoSaveFileName), successMessageTimeout); const bool hadClonedDocument = bool(optionalClonedDocument); bool started = false; if (d->image->isIdle() || hadClonedDocument) { started = initiateSavingInBackground(i18n("Autosaving..."), this, SLOT(slotCompleteAutoSaving(KritaUtils::ExportFileJob,KisImportExportFilter::ConversionStatus,QString)), KritaUtils::ExportFileJob(autoSaveFileName, nativeFormatMimeType(), KritaUtils::SaveIsExporting | KritaUtils::SaveInAutosaveMode), 0, std::move(optionalClonedDocument)); } else { emit statusBarMessage(i18n("Autosaving postponed: document is busy..."), errorMessageTimeout); } if (!started && !hadClonedDocument && d->autoSaveFailureCount >= 3) { KisCloneDocumentStroke *stroke = new KisCloneDocumentStroke(this); connect(stroke, SIGNAL(sigDocumentCloned(KisDocument*)), this, SLOT(slotInitiateAsyncAutosaving(KisDocument*)), Qt::BlockingQueuedConnection); KisStrokeId strokeId = d->image->startStroke(stroke); d->image->endStroke(strokeId); setInfiniteAutoSaveInterval(); } else if (!started) { setEmergencyAutoSaveInterval(); } else { d->modifiedAfterAutosave = false; } } void KisDocument::slotAutoSave() { slotAutoSaveImpl(std::unique_ptr()); } void KisDocument::slotInitiateAsyncAutosaving(KisDocument *clonedDocument) { slotAutoSaveImpl(std::unique_ptr(clonedDocument)); } void KisDocument::slotCompleteAutoSaving(const KritaUtils::ExportFileJob &job, KisImportExportFilter::ConversionStatus status, const QString &errorMessage) { Q_UNUSED(job); const QString fileName = QFileInfo(job.filePath).fileName(); if (status != KisImportExportFilter::OK) { setEmergencyAutoSaveInterval(); emit statusBarMessage(i18nc("%1 --- failing file name, %2 --- error message", "Error during autosaving %1: %2", fileName, exportErrorToUserMessage(status, errorMessage)), errorMessageTimeout); } else { KisConfig cfg(true); d->autoSaveDelay = cfg.autoSaveInterval(); if (!d->modifiedWhileSaving) { d->autoSaveTimer->stop(); // until the next change d->autoSaveFailureCount = 0; } else { setNormalAutoSaveInterval(); } emit statusBarMessage(i18n("Finished autosaving %1", fileName), successMessageTimeout); } } bool KisDocument::startExportInBackground(const QString &actionName, const QString &location, const QString &realLocation, const QByteArray &mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration) { d->savingImage = d->image; KisMainWindow *window = KisPart::instance()->currentMainwindow(); if (window) { if (window->viewManager()) { d->savingUpdater = window->viewManager()->createThreadedUpdater(actionName); d->importExportManager->setUpdater(d->savingUpdater); } } KisImportExportFilter::ConversionStatus initializationStatus; d->childSavingFuture = d->importExportManager->exportDocumentAsyc(location, realLocation, mimeType, initializationStatus, showWarnings, exportConfiguration); if (initializationStatus != KisImportExportFilter::ConversionStatus::OK) { if (d->savingUpdater) { d->savingUpdater->cancel(); } d->savingImage.clear(); emit sigBackgroundSavingFinished(initializationStatus, this->errorMessage()); return false; } typedef QFutureWatcher StatusWatcher; StatusWatcher *watcher = new StatusWatcher(); watcher->setFuture(d->childSavingFuture); connect(watcher, SIGNAL(finished()), SLOT(finishExportInBackground())); connect(watcher, SIGNAL(finished()), watcher, SLOT(deleteLater())); return true; } void KisDocument::finishExportInBackground() { KIS_SAFE_ASSERT_RECOVER(d->childSavingFuture.isFinished()) { emit sigBackgroundSavingFinished(KisImportExportFilter::InternalError, ""); return; } KisImportExportFilter::ConversionStatus status = d->childSavingFuture.result(); const QString errorMessage = this->errorMessage(); d->savingImage.clear(); d->childSavingFuture = QFuture(); d->lastErrorMessage.clear(); if (d->savingUpdater) { d->savingUpdater->setProgress(100); } emit sigBackgroundSavingFinished(status, errorMessage); } void KisDocument::setReadWrite(bool readwrite) { d->readwrite = readwrite; setNormalAutoSaveInterval(); Q_FOREACH (KisMainWindow *mainWindow, KisPart::instance()->mainWindows()) { mainWindow->setReadWrite(readwrite); } } void KisDocument::setAutoSaveDelay(int delay) { if (isReadWrite() && delay > 0) { d->autoSaveTimer->start(delay * 1000); } else { d->autoSaveTimer->stop(); } } void KisDocument::setNormalAutoSaveInterval() { setAutoSaveDelay(d->autoSaveDelay); d->autoSaveFailureCount = 0; } void KisDocument::setEmergencyAutoSaveInterval() { const int emergencyAutoSaveInterval = 10; /* sec */ setAutoSaveDelay(emergencyAutoSaveInterval); d->autoSaveFailureCount++; } void KisDocument::setInfiniteAutoSaveInterval() { setAutoSaveDelay(-1); } KoDocumentInfo *KisDocument::documentInfo() const { return d->docInfo; } bool KisDocument::isModified() const { return d->modified; } QPixmap KisDocument::generatePreview(const QSize& size) { KisImageSP image = d->image; if (d->savingImage) image = d->savingImage; if (image) { QRect bounds = image->bounds(); QSize newSize = bounds.size(); newSize.scale(size, Qt::KeepAspectRatio); QPixmap px = QPixmap::fromImage(image->convertToQImage(newSize, 0)); if (px.size() == QSize(0,0)) { px = QPixmap(newSize); QPainter gc(&px); QBrush checkBrush = QBrush(KisCanvasWidgetBase::createCheckersImage(newSize.width() / 5)); gc.fillRect(px.rect(), checkBrush); gc.end(); } return px; } return QPixmap(size); } QString KisDocument::generateAutoSaveFileName(const QString & path) const { QString retval; // Using the extension allows to avoid relying on the mime magic when opening const QString extension (".kra"); QRegularExpression autosavePattern("^\\..+-autosave.kra$"); QFileInfo fi(path); QString dir = fi.absolutePath(); QString filename = fi.fileName(); if (path.isEmpty() || autosavePattern.match(filename).hasMatch()) { // Never saved? #ifdef Q_OS_WIN // On Windows, use the temp location (https://bugs.kde.org/show_bug.cgi?id=314921) retval = QString("%1%2.%3-%4-%5-autosave%6").arg(QDir::tempPath()).arg(QDir::separator()).arg("krita").arg(qApp->applicationPid()).arg(objectName()).arg(extension); #else // On Linux, use a temp file in $HOME then. Mark it with the pid so two instances don't overwrite each other's autosave file retval = QString("%1%2.%3-%4-%5-autosave%6").arg(QDir::homePath()).arg(QDir::separator()).arg("krita").arg(qApp->applicationPid()).arg(objectName()).arg(extension); #endif } else { retval = QString("%1%2.%3-autosave%4").arg(dir).arg(QDir::separator()).arg(filename).arg(extension); } //qDebug() << "generateAutoSaveFileName() for path" << path << ":" << retval; return retval; } bool KisDocument::importDocument(const QUrl &_url) { bool ret; dbgUI << "url=" << _url.url(); // open... ret = openUrl(_url); // reset url & m_file (kindly? set by KisParts::openUrl()) to simulate a // File --> Import if (ret) { dbgUI << "success, resetting url"; resetURL(); setTitleModified(); } return ret; } bool KisDocument::openUrl(const QUrl &_url, OpenFlags flags) { if (!_url.isLocalFile()) { return false; } dbgUI << "url=" << _url.url(); d->lastErrorMessage.clear(); // Reimplemented, to add a check for autosave files and to improve error reporting if (!_url.isValid()) { d->lastErrorMessage = i18n("Malformed URL\n%1", _url.url()); // ## used anywhere ? return false; } QUrl url(_url); bool autosaveOpened = false; if (url.isLocalFile() && !fileBatchMode()) { QString file = url.toLocalFile(); QString asf = generateAutoSaveFileName(file); if (QFile::exists(asf)) { KisApplication *kisApp = static_cast(qApp); kisApp->hideSplashScreen(); //dbgUI <<"asf=" << asf; // ## TODO compare timestamps ? int res = QMessageBox::warning(0, i18nc("@title:window", "Krita"), i18n("An autosaved file exists for this document.\nDo you want to open the autosaved file instead?"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes); switch (res) { case QMessageBox::Yes : url.setPath(asf); autosaveOpened = true; break; case QMessageBox::No : QFile::remove(asf); break; default: // Cancel return false; } } } bool ret = openUrlInternal(url); if (autosaveOpened || flags & RecoveryFile) { setReadWrite(true); // enable save button setModified(true); setRecovered(true); } else { if (!(flags & DontAddToRecent)) { KisPart::instance()->addRecentURLToAllMainWindows(_url); } if (ret) { // Detect readonly local-files; remote files are assumed to be writable QFileInfo fi(url.toLocalFile()); setReadWrite(fi.isWritable()); } setRecovered(false); } return ret; } class DlgLoadMessages : public KoDialog { public: DlgLoadMessages(const QString &title, const QString &message, const QStringList &warnings) { setWindowTitle(title); setWindowIcon(KisIconUtils::loadIcon("warning")); QWidget *page = new QWidget(this); QVBoxLayout *layout = new QVBoxLayout(page); QHBoxLayout *hlayout = new QHBoxLayout(); QLabel *labelWarning= new QLabel(); labelWarning->setPixmap(KisIconUtils::loadIcon("warning").pixmap(32, 32)); hlayout->addWidget(labelWarning); hlayout->addWidget(new QLabel(message)); layout->addLayout(hlayout); QTextBrowser *browser = new QTextBrowser(); QString warning = "

"; if (warnings.size() == 1) { warning += " Reason:

"; } else { warning += " Reasons:

"; } warning += "

    "; Q_FOREACH(const QString &w, warnings) { warning += "\n
  • " + w + "
  • "; } warning += "
"; browser->setHtml(warning); browser->setMinimumHeight(200); browser->setMinimumWidth(400); layout->addWidget(browser); setMainWidget(page); setButtons(KoDialog::Ok); resize(minimumSize()); } }; bool KisDocument::openFile() { //dbgUI <<"for" << localFilePath(); if (!QFile::exists(localFilePath())) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("File %1 does not exist.", localFilePath())); return false; } QString filename = localFilePath(); QString typeName = mimeType(); if (typeName.isEmpty()) { typeName = KisMimeDatabase::mimeTypeForFile(filename); } //qDebug() << "mimetypes 4:" << typeName; // Allow to open backup files, don't keep the mimetype application/x-trash. if (typeName == "application/x-trash") { QString path = filename; while (path.length() > 0) { path.chop(1); typeName = KisMimeDatabase::mimeTypeForFile(path); //qDebug() << "\t" << path << typeName; if (!typeName.isEmpty()) { break; } } //qDebug() << "chopped" << filename << "to" << path << "Was trash, is" << typeName; } dbgUI << localFilePath() << "type:" << typeName; KisMainWindow *window = KisPart::instance()->currentMainwindow(); if (window && window->viewManager()) { KoUpdaterPtr updater = window->viewManager()->createUnthreadedUpdater(i18n("Opening document")); d->importExportManager->setUpdater(updater); } KisImportExportFilter::ConversionStatus status; status = d->importExportManager->importDocument(localFilePath(), typeName); if (status != KisImportExportFilter::OK) { QString msg = KisImportExportFilter::conversionStatusString(status); if (!msg.isEmpty()) { DlgLoadMessages dlg(i18nc("@title:window", "Krita"), i18n("Could not open %2.\nReason: %1.", msg, prettyPathOrUrl()), errorMessage().split("\n") + warningMessage().split("\n")); dlg.exec(); } return false; } else if (!warningMessage().isEmpty()) { DlgLoadMessages dlg(i18nc("@title:window", "Krita"), i18n("There were problems opening %1.", prettyPathOrUrl()), warningMessage().split("\n")); dlg.exec(); setUrl(QUrl()); } setMimeTypeAfterLoading(typeName); emit sigLoadingFinished(); undoStack()->clear(); return true; } // shared between openFile and koMainWindow's "create new empty document" code void KisDocument::setMimeTypeAfterLoading(const QString& mimeType) { d->mimeType = mimeType.toLatin1(); d->outputMimeType = d->mimeType; } bool KisDocument::loadNativeFormat(const QString & file_) { return openUrl(QUrl::fromLocalFile(file_)); } void KisDocument::setModified(bool mod) { if (mod) { updateEditingTime(false); } if (d->isAutosaving) // ignore setModified calls due to autosaving return; if ( !d->readwrite && d->modified ) { errKrita << "Can't set a read-only document to 'modified' !" << endl; return; } //dbgUI<<" url:" << url.path(); //dbgUI<<" mod="<docInfo->aboutInfo("editing-time").toInt() + d->firstMod.secsTo(d->lastMod))); d->firstMod = now; } else if (firstModDelta > 60 || forceStoreElapsed) { d->docInfo->setAboutInfo("editing-time", QString::number(d->docInfo->aboutInfo("editing-time").toInt() + firstModDelta)); d->firstMod = now; } d->lastMod = now; } QString KisDocument::prettyPathOrUrl() const { QString _url(url().toDisplayString()); #ifdef Q_OS_WIN if (url().isLocalFile()) { _url = QDir::toNativeSeparators(_url); } #endif return _url; } // Get caption from document info (title(), in about page) QString KisDocument::caption() const { QString c; const QString _url(url().fileName()); // if URL is empty...it is probably an unsaved file if (_url.isEmpty()) { c = " [" + i18n("Not Saved") + "] "; } else { c = _url; // Fall back to document URL } return c; } void KisDocument::setTitleModified() { emit titleModified(caption(), isModified()); } QDomDocument KisDocument::createDomDocument(const QString& tagName, const QString& version) const { return createDomDocument("krita", tagName, version); } //static QDomDocument KisDocument::createDomDocument(const QString& appName, const QString& tagName, const QString& version) { QDomImplementation impl; QString url = QString("http://www.calligra.org/DTD/%1-%2.dtd").arg(appName).arg(version); QDomDocumentType dtype = impl.createDocumentType(tagName, QString("-//KDE//DTD %1 %2//EN").arg(appName).arg(version), url); // The namespace URN doesn't need to include the version number. QString namespaceURN = QString("http://www.calligra.org/DTD/%1").arg(appName); QDomDocument doc = impl.createDocument(namespaceURN, tagName, dtype); doc.insertBefore(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\""), doc.documentElement()); return doc; } bool KisDocument::isNativeFormat(const QByteArray& mimetype) const { if (mimetype == nativeFormatMimeType()) return true; return extraNativeMimeTypes().contains(mimetype); } void KisDocument::setErrorMessage(const QString& errMsg) { d->lastErrorMessage = errMsg; } QString KisDocument::errorMessage() const { return d->lastErrorMessage; } void KisDocument::setWarningMessage(const QString& warningMsg) { d->lastWarningMessage = warningMsg; } QString KisDocument::warningMessage() const { return d->lastWarningMessage; } void KisDocument::removeAutoSaveFiles(const QString &autosaveBaseName, bool wasRecovered) { //qDebug() << "removeAutoSaveFiles"; // Eliminate any auto-save file QString asf = generateAutoSaveFileName(autosaveBaseName); // the one in the current dir //qDebug() << "\tfilename:" << asf << "exists:" << QFile::exists(asf); if (QFile::exists(asf)) { //qDebug() << "\tremoving autosavefile" << asf; QFile::remove(asf); } asf = generateAutoSaveFileName(QString()); // and the one in $HOME //qDebug() << "Autsavefile in $home" << asf; if (QFile::exists(asf)) { //qDebug() << "\tremoving autsavefile 2" << asf; QFile::remove(asf); } QRegularExpression autosavePattern("^\\..+-autosave.kra$"); if (wasRecovered && !autosaveBaseName.isEmpty() && autosavePattern.match(QFileInfo(autosaveBaseName).fileName()).hasMatch() && QFile::exists(autosaveBaseName)) { QFile::remove(autosaveBaseName); } } KoUnit KisDocument::unit() const { return d->unit; } void KisDocument::setUnit(const KoUnit &unit) { if (d->unit != unit) { d->unit = unit; emit unitChanged(unit); } } KUndo2Stack *KisDocument::undoStack() { return d->undoStack; } KisImportExportManager *KisDocument::importExportManager() const { return d->importExportManager; } void KisDocument::addCommand(KUndo2Command *command) { if (command) d->undoStack->push(command); } void KisDocument::beginMacro(const KUndo2MagicString & text) { d->undoStack->beginMacro(text); } void KisDocument::endMacro() { d->undoStack->endMacro(); } void KisDocument::slotUndoStackCleanChanged(bool value) { setModified(!value); } void KisDocument::slotConfigChanged() { KisConfig cfg(true); d->undoStack->setUndoLimit(cfg.undoStackLimit()); d->autoSaveDelay = cfg.autoSaveInterval(); setNormalAutoSaveInterval(); } void KisDocument::clearUndoHistory() { d->undoStack->clear(); } KisGridConfig KisDocument::gridConfig() const { return d->gridConfig; } void KisDocument::setGridConfig(const KisGridConfig &config) { d->gridConfig = config; } -QList &KisDocument::paletteList() +QList &KisDocument::paletteList() { return d->paletteList; } -void KisDocument::setPaletteList(const QList &paletteList) +void KisDocument::setPaletteList(const QList &paletteList) { d->paletteList = paletteList; } const KisGuidesConfig& KisDocument::guidesConfig() const { return d->guidesConfig; } void KisDocument::setGuidesConfig(const KisGuidesConfig &data) { if (d->guidesConfig == data) return; d->guidesConfig = data; emit sigGuidesConfigChanged(d->guidesConfig); } void KisDocument::resetURL() { setUrl(QUrl()); setLocalFilePath(QString()); } KoDocumentInfoDlg *KisDocument::createDocumentInfoDialog(QWidget *parent, KoDocumentInfo *docInfo) const { return new KoDocumentInfoDlg(parent, docInfo); } bool KisDocument::isReadWrite() const { return d->readwrite; } QUrl KisDocument::url() const { return d->m_url; } bool KisDocument::closeUrl(bool promptToSave) { if (promptToSave) { if ( isReadWrite() && isModified()) { Q_FOREACH (KisView *view, KisPart::instance()->views()) { if (view && view->document() == this) { if (!view->queryClose()) { return false; } } } } } // Not modified => ok and delete temp file. d->mimeType = QByteArray(); // It always succeeds for a read-only part, // but the return value exists for reimplementations // (e.g. pressing cancel for a modified read-write part) return true; } void KisDocument::setUrl(const QUrl &url) { d->m_url = url; } QString KisDocument::localFilePath() const { return d->m_file; } void KisDocument::setLocalFilePath( const QString &localFilePath ) { d->m_file = localFilePath; } bool KisDocument::openUrlInternal(const QUrl &url) { if ( !url.isValid() ) return false; if (d->m_bAutoDetectedMime) { d->mimeType = QByteArray(); d->m_bAutoDetectedMime = false; } QByteArray mimetype = d->mimeType; if ( !closeUrl() ) return false; d->mimeType = mimetype; setUrl(url); d->m_file.clear(); if (d->m_url.isLocalFile()) { d->m_file = d->m_url.toLocalFile(); bool ret; // set the mimetype only if it was not already set (for example, by the host application) if (d->mimeType.isEmpty()) { // get the mimetype of the file // using findByUrl() to avoid another string -> url conversion QString mime = KisMimeDatabase::mimeTypeForFile(d->m_url.toLocalFile()); d->mimeType = mime.toLocal8Bit(); d->m_bAutoDetectedMime = true; } setUrl(d->m_url); ret = openFile(); if (ret) { emit completed(); } else { emit canceled(QString()); } return ret; } return false; } bool KisDocument::newImage(const QString& name, qint32 width, qint32 height, const KoColorSpace* cs, const KoColor &bgColor, bool backgroundAsLayer, int numberOfLayers, const QString &description, const double imageResolution) { Q_ASSERT(cs); KisImageSP image; KisPaintLayerSP layer; if (!cs) return false; QApplication::setOverrideCursor(Qt::BusyCursor); image = new KisImage(createUndoStore(), width, height, cs, name); Q_CHECK_PTR(image); connect(image, SIGNAL(sigImageModified()), this, SLOT(setImageModified()), Qt::UniqueConnection); image->setResolution(imageResolution, imageResolution); image->assignImageProfile(cs->profile()); documentInfo()->setAboutInfo("title", name); documentInfo()->setAboutInfo("abstract", description); layer = new KisPaintLayer(image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8, cs); Q_CHECK_PTR(layer); if (backgroundAsLayer) { image->setDefaultProjectionColor(KoColor(cs)); if (bgColor.opacityU8() == OPACITY_OPAQUE_U8) { layer->paintDevice()->setDefaultPixel(bgColor); } else { // Hack: with a semi-transparent background color, the projection isn't composited right if we just set the default pixel KisFillPainter painter; painter.begin(layer->paintDevice()); painter.fillRect(0, 0, width, height, bgColor, bgColor.opacityU8()); } } else { image->setDefaultProjectionColor(bgColor); } layer->setDirty(QRect(0, 0, width, height)); image->addNode(layer.data(), image->rootLayer().data()); setCurrentImage(image); for(int i = 1; i < numberOfLayers; ++i) { KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), OPACITY_OPAQUE_U8, cs); image->addNode(layer, image->root(), i); layer->setDirty(QRect(0, 0, width, height)); } KisConfig cfg(false); cfg.defImageWidth(width); cfg.defImageHeight(height); cfg.defImageResolution(imageResolution); cfg.defColorModel(image->colorSpace()->colorModelId().id()); cfg.setDefaultColorDepth(image->colorSpace()->colorDepthId().id()); cfg.defColorProfile(image->colorSpace()->profile()->name()); QApplication::restoreOverrideCursor(); return true; } bool KisDocument::isSaving() const { const bool result = d->savingMutex.tryLock(); if (result) { d->savingMutex.unlock(); } return !result; } void KisDocument::waitForSavingToComplete() { if (isSaving()) { KisAsyncActionFeedback f(i18nc("progress dialog message when the user closes the document that is being saved", "Waiting for saving to complete..."), 0); f.waitForMutex(&d->savingMutex); } } KoShapeControllerBase *KisDocument::shapeController() const { return d->shapeController; } KoShapeLayer* KisDocument::shapeForNode(KisNodeSP layer) const { return d->shapeController->shapeForNode(layer); } QList KisDocument::assistants() const { return d->assistants; } void KisDocument::setAssistants(const QList &value) { d->assistants = value; } KisSharedPtr KisDocument::referenceImagesLayer() const { return d->referenceImagesLayer.data(); } void KisDocument::setReferenceImagesLayer(KisSharedPtr layer, bool updateImage) { if (d->referenceImagesLayer) { d->referenceImagesLayer->disconnect(this); } if (updateImage) { if (layer) { d->image->addNode(layer); } else { d->image->removeNode(d->referenceImagesLayer); } } d->referenceImagesLayer = layer; if (d->referenceImagesLayer) { connect(d->referenceImagesLayer, SIGNAL(sigUpdateCanvas(QRectF)), this, SIGNAL(sigReferenceImagesChanged())); } } void KisDocument::setPreActivatedNode(KisNodeSP activatedNode) { d->preActivatedNode = activatedNode; } KisNodeSP KisDocument::preActivatedNode() const { return d->preActivatedNode; } KisImageWSP KisDocument::image() const { return d->image; } KisImageSP KisDocument::savingImage() const { return d->savingImage; } void KisDocument::setCurrentImage(KisImageSP image, bool forceInitialUpdate) { if (d->image) { // Disconnect existing sig/slot connections d->image->setUndoStore(new KisDumbUndoStore()); d->image->disconnect(this); d->shapeController->setImage(0); d->image = 0; } if (!image) return; d->setImageAndInitIdleWatcher(image); d->image->setUndoStore(new KisDocumentUndoStore(this)); d->shapeController->setImage(image); setModified(false); connect(d->image, SIGNAL(sigImageModified()), this, SLOT(setImageModified()), Qt::UniqueConnection); if (forceInitialUpdate) { d->image->initialRefreshGraph(); } } void KisDocument::hackPreliminarySetImage(KisImageSP image) { KIS_SAFE_ASSERT_RECOVER_RETURN(!d->image); d->setImageAndInitIdleWatcher(image); d->shapeController->setImage(image); } void KisDocument::setImageModified() { setModified(true); } KisUndoStore* KisDocument::createUndoStore() { return new KisDocumentUndoStore(this); } bool KisDocument::isAutosaving() const { return d->isAutosaving; } QString KisDocument::exportErrorToUserMessage(KisImportExportFilter::ConversionStatus status, const QString &errorMessage) { return errorMessage.isEmpty() ? KisImportExportFilter::conversionStatusString(status) : errorMessage; } void KisDocument::setAssistantsGlobalColor(QColor color) { d->globalAssistantsColor = color; } QColor KisDocument::assistantsGlobalColor() { return d->globalAssistantsColor; } QRectF KisDocument::documentBounds() const { QRectF bounds = d->image->bounds(); if (d->referenceImagesLayer) { bounds |= d->referenceImagesLayer->boundingImageRect(); } return bounds; } diff --git a/libs/ui/KisDocument.h b/libs/ui/KisDocument.h index 11f80ba458..a661ecaef5 100644 --- a/libs/ui/KisDocument.h +++ b/libs/ui/KisDocument.h @@ -1,655 +1,655 @@ /* This file is part of the Krita project * * Copyright (C) 2014 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KISDOCUMENT_H #define KISDOCUMENT_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kritaui_export.h" #include class QString; class KUndo2Command; class KoUnit; class KoColor; class KoColorSpace; class KoShapeControllerBase; class KoShapeLayer; class KoStore; class KoOdfReadStore; class KoDocumentInfo; class KoDocumentInfoDlg; class KisImportExportManager; class KisUndoStore; class KisPart; class KisGridConfig; class KisGuidesConfig; class QDomDocument; class KisReferenceImagesLayer; #define KIS_MIME_TYPE "application/x-krita" /** * The %Calligra document class * * This class provides some functionality each %Calligra document should have. * * @short The %Calligra document class */ class KRITAUI_EXPORT KisDocument : public QObject, public KoDocumentBase { Q_OBJECT protected: explicit KisDocument(); /** * @brief KisDocument makes a deep copy of the document \p rhs. * The caller *must* ensure that the image is properly * locked and is in consistent state before asking for * cloning. * @param rhs the source document to copy from */ explicit KisDocument(const KisDocument &rhs); public: enum OpenFlag { None = 0, DontAddToRecent = 0x1, RecoveryFile = 0x2 }; Q_DECLARE_FLAGS(OpenFlags, OpenFlag) /** * Destructor. * * The destructor does not delete any attached KisView objects and it does not * delete the attached widget as returned by widget(). */ ~KisDocument() override; /** * @brief reload Reloads the document from the original url * @return the result of loading the document */ bool reload(); /** * @brief creates a clone of the document and returns it. Please make sure that you * hold all the necessary locks on the image before asking for a clone! */ KisDocument* clone(); /** * @brief openUrl Open an URL * @param url The URL to open * @param flags Control specific behavior * @return success status */ bool openUrl(const QUrl &url, OpenFlags flags = None); /** * Opens the document given by @p url, without storing the URL * in the KisDocument. * Call this instead of openUrl() to implement KisMainWindow's * File --> Import feature. * * @note This will call openUrl(). To differentiate this from an ordinary * Open operation (in any reimplementation of openUrl() or openFile()) * call isImporting(). */ bool importDocument(const QUrl &url); /** * Saves the document as @p url without changing the state of the * KisDocument (URL, modified flag etc.). Call this instead of * KisParts::ReadWritePart::saveAs() to implement KisMainWindow's * File --> Export feature. */ bool exportDocument(const QUrl &url, const QByteArray &mimeType, bool showWarnings = false, KisPropertiesConfigurationSP exportConfiguration = 0); bool exportDocumentSync(const QUrl &url, const QByteArray &mimeType, KisPropertiesConfigurationSP exportConfiguration = 0); private: bool exportDocumentImpl(const KritaUtils::ExportFileJob &job, KisPropertiesConfigurationSP exportConfiguration); public: /** * @brief Sets whether the document can be edited or is read only. * * This recursively applied to all child documents and * KisView::updateReadWrite is called for every attached * view. */ void setReadWrite(bool readwrite = true); /** * To be preferred when a document exists. It is fast when calling * it multiple times since it caches the result that readNativeFormatMimeType() * delivers. * This comes from the X-KDE-NativeMimeType key in the .desktop file. */ static QByteArray nativeFormatMimeType() { return KIS_MIME_TYPE; } /// Checks whether a given mimetype can be handled natively. bool isNativeFormat(const QByteArray& mimetype) const; /// Returns a list of the mimetypes considered "native", i.e. which can /// be saved by KisDocument without a filter, in *addition* to the main one static QStringList extraNativeMimeTypes() { return QStringList() << KIS_MIME_TYPE; } /** * Returns the actual mimetype of the document */ QByteArray mimeType() const override; /** * @brief Sets the mime type for the document. * * When choosing "save as" this is also the mime type * selected by default. */ void setMimeType(const QByteArray & mimeType) override; /** * @return true if file operations should inhibit the option dialog */ bool fileBatchMode() const; /** * @param batchMode if true, do not show the option dialog for file operations. */ void setFileBatchMode(const bool batchMode); /** * Sets the error message to be shown to the user (use i18n()!) * when loading or saving fails. * If you asked the user about something and they chose "Cancel", */ void setErrorMessage(const QString& errMsg); /** * Return the last error message. Usually KisDocument takes care of * showing it; this method is mostly provided for non-interactive use. */ QString errorMessage() const; /** * Sets the warning message to be shown to the user (use i18n()!) * when loading or saving fails. */ void setWarningMessage(const QString& warningMsg); /** * Return the last warning message set by loading or saving. Warnings * mean that the document could not be completely loaded, but the errors * were not absolutely fatal. */ QString warningMessage() const; /** * @brief Generates a preview picture of the document * @note The preview is used in the File Dialog and also to create the Thumbnail */ QPixmap generatePreview(const QSize& size); /** * Tells the document that its title has been modified, either because * the modified status changes (this is done by setModified() ) or * because the URL or the document-info's title changed. */ void setTitleModified(); /** * @brief Sets the document to empty. * * Used after loading a template * (which is not empty, but not the user's input). * * @see isEmpty() */ void setEmpty(bool empty = true); /** * Return a correctly created QDomDocument for this KisDocument, * including processing instruction, complete DOCTYPE tag (with systemId and publicId), and root element. * @param tagName the name of the tag for the root element * @param version the DTD version (usually the application's version). */ QDomDocument createDomDocument(const QString& tagName, const QString& version) const; /** * Return a correctly created QDomDocument for an old (1.3-style) %Calligra document, * including processing instruction, complete DOCTYPE tag (with systemId and publicId), and root element. * This static method can be used e.g. by filters. * @param appName the app's instance name, e.g. words, kspread, kpresenter etc. * @param tagName the name of the tag for the root element, e.g. DOC for words/kpresenter. * @param version the DTD version (usually the application's version). */ static QDomDocument createDomDocument(const QString& appName, const QString& tagName, const QString& version); /** * Loads a document in the native format from a given URL. * Reimplement if your native format isn't XML. * * @param file the file to load - usually KReadOnlyPart::m_file or the result of a filter */ bool loadNativeFormat(const QString & file); /** * Set standard autosave interval that is set by a config file */ void setNormalAutoSaveInterval(); /** * Set emergency interval that autosave uses when the image is busy, * by default it is 10 sec */ void setEmergencyAutoSaveInterval(); /** * Disable autosave */ void setInfiniteAutoSaveInterval(); /** * @return the information concerning this document. * @see KoDocumentInfo */ KoDocumentInfo *documentInfo() const; /** * Performs a cleanup of unneeded backup files */ void removeAutoSaveFiles(const QString &autosaveBaseName, bool wasRecovered); /** * Returns true if this document or any of its internal child documents are modified. */ bool isModified() const override; /** * @return caption of the document * * Caption is of the form "[title] - [url]", * built out of the document info (title) and pretty-printed * document URL. * If the title is not present, only the URL it returned. */ QString caption() const; /** * Sets the document URL to empty URL * KParts doesn't allow this, but %Calligra apps have e.g. templates * After using loadNativeFormat on a template, one wants * to set the url to QUrl() */ void resetURL(); /** * @internal (public for KisMainWindow) */ void setMimeTypeAfterLoading(const QString& mimeType); /** * Returns the unit used to display all measures/distances. */ KoUnit unit() const; /** * Sets the unit used to display all measures/distances. */ void setUnit(const KoUnit &unit); KisGridConfig gridConfig() const; void setGridConfig(const KisGridConfig &config); /// returns the guides data for this document. const KisGuidesConfig& guidesConfig() const; void setGuidesConfig(const KisGuidesConfig &data); - QList &paletteList(); - void setPaletteList(const QList &paletteList); + QList &paletteList(); + void setPaletteList(const QList &paletteList); void clearUndoHistory(); /** * Sets the modified flag on the document. This means that it has * to be saved or not before deleting it. */ void setModified(bool _mod); void setRecovered(bool value); bool isRecovered() const; void updateEditingTime(bool forceStoreElapsed); /** * Returns the global undo stack */ KUndo2Stack *undoStack(); /** * @brief importExportManager gives access to the internal import/export manager * @return the document's import/export manager */ KisImportExportManager *importExportManager() const; /** * @brief serializeToNativeByteArray daves the document into a .kra file wtitten * to a memory-based byte-array * @return a byte array containing the .kra file */ QByteArray serializeToNativeByteArray(); /** * @brief isInSaving shown if the document has any (background) saving process or not * @return true if there is some saving in action */ bool isInSaving() const; public Q_SLOTS: /** * Adds a command to the undo stack and executes it by calling the redo() function. * @param command command to add to the undo stack */ void addCommand(KUndo2Command *command); /** * Begins recording of a macro command. At the end endMacro needs to be called. * @param text command description */ void beginMacro(const KUndo2MagicString &text); /** * Ends the recording of a macro command. */ void endMacro(); Q_SIGNALS: /** * This signal is emitted when the unit is changed by setUnit(). * It is common to connect views to it, in order to change the displayed units * (e.g. in the rulers) */ void unitChanged(const KoUnit &unit); /** * Emitted e.g. at the beginning of a save operation * This is emitted by KisDocument and used by KisView to display a statusbar message */ void statusBarMessage(const QString& text, int timeout = 0); /** * Emitted e.g. at the end of a save operation * This is emitted by KisDocument and used by KisView to clear the statusbar message */ void clearStatusBarMessage(); /** * Emitted when the document is modified */ void modified(bool); void titleModified(const QString &caption, bool isModified); void sigLoadingFinished(); void sigSavingFinished(); void sigGuidesConfigChanged(const KisGuidesConfig &config); void sigBackgroundSavingFinished(KisImportExportFilter::ConversionStatus status, const QString &errorMessage); void sigCompleteBackgroundSaving(const KritaUtils::ExportFileJob &job, KisImportExportFilter::ConversionStatus status, const QString &errorMessage); void sigReferenceImagesChanged(); private Q_SLOTS: void finishExportInBackground(); void slotChildCompletedSavingInBackground(KisImportExportFilter::ConversionStatus status, const QString &errorMessage); void slotCompleteAutoSaving(const KritaUtils::ExportFileJob &job, KisImportExportFilter::ConversionStatus status, const QString &errorMessage); void slotCompleteSavingDocument(const KritaUtils::ExportFileJob &job, KisImportExportFilter::ConversionStatus status, const QString &errorMessage); void slotInitiateAsyncAutosaving(KisDocument *clonedDocument); private: friend class KisPart; friend class SafeSavingLocker; bool initiateSavingInBackground(const QString actionName, const QObject *receiverObject, const char *receiverMethod, const KritaUtils::ExportFileJob &job, KisPropertiesConfigurationSP exportConfiguration, std::unique_ptr &&optionalClonedDocument); bool initiateSavingInBackground(const QString actionName, const QObject *receiverObject, const char *receiverMethod, const KritaUtils::ExportFileJob &job, KisPropertiesConfigurationSP exportConfiguration); bool startExportInBackground(const QString &actionName, const QString &location, const QString &realLocation, const QByteArray &mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration); /** * Activate/deactivate/configure the autosave feature. * @param delay in seconds, 0 to disable */ void setAutoSaveDelay(int delay); /** * Generate a name for the document. */ QString newObjectName(); QString generateAutoSaveFileName(const QString & path) const; /** * Loads a document * * Applies a filter if necessary, and calls loadNativeFormat in any case * You should not have to reimplement, except for very special cases. * * NOTE: this method also creates a new KisView instance! * * This method is called from the KReadOnlyPart::openUrl method. */ bool openFile(); public: bool isAutosaving() const override; public: QString localFilePath() const override; void setLocalFilePath( const QString &localFilePath ); KoDocumentInfoDlg* createDocumentInfoDialog(QWidget *parent, KoDocumentInfo *docInfo) const; bool isReadWrite() const; QUrl url() const override; void setUrl(const QUrl &url) override; bool closeUrl(bool promptToSave = true); bool saveAs(const QUrl &url, const QByteArray &mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfigration = 0); /** * Create a new image that has this document as a parent and * replace the current image with this image. */ bool newImage(const QString& name, qint32 width, qint32 height, const KoColorSpace * cs, const KoColor &bgColor, bool backgroundAsLayer, int numberOfLayers, const QString &imageDescription, const double imageResolution); bool isSaving() const; void waitForSavingToComplete(); KisImageWSP image() const; /** * @brief savingImage provides a detached, shallow copy of the original image that must be used when saving. * Any strokes in progress will not be applied to this image, so the result might be missing some data. On * the other hand, it won't block. * * @return a shallow copy of the original image, or 0 is saving is not in progress */ KisImageSP savingImage() const; /** * Set the current image to the specified image and turn undo on. */ void setCurrentImage(KisImageSP image, bool forceInitialUpdate = true); /** * Set the image of the document preliminary, before the document * has completed loading. Some of the document items (shapes) may want * to access image properties (bounds and resolution), so we should provide * it to them even before the entire image is loaded. * * Right now, the only use by KoShapeRegistry::createShapeFromOdf(), remove * after it is deprecated. */ void hackPreliminarySetImage(KisImageSP image); KisUndoStore* createUndoStore(); /** * The shape controller matches internal krita image layers with * the flake shape hierarchy. */ KoShapeControllerBase * shapeController() const; KoShapeLayer* shapeForNode(KisNodeSP layer) const; /** * Set the list of nodes that was marked as currently active. Used *only* * for saving loading. Never use it for tools or processing. */ void setPreActivatedNode(KisNodeSP activatedNode); /** * @return the node that was set as active during loading. Used *only* * for saving loading. Never use it for tools or processing. */ KisNodeSP preActivatedNode() const; /// @return the list of assistants associated with this document QList assistants() const; /// @replace the current list of assistants with @param value void setAssistants(const QList &value); void setAssistantsGlobalColor(QColor color); QColor assistantsGlobalColor(); /** * Get existing reference images layer or null if none exists. */ KisSharedPtr referenceImagesLayer() const; void setReferenceImagesLayer(KisSharedPtr layer, bool updateImage); bool save(bool showWarnings, KisPropertiesConfigurationSP exportConfiguration); /** * Return the bounding box of the image and associated elements (e.g. reference images) */ QRectF documentBounds() const; Q_SIGNALS: void completed(); void canceled(const QString &); private Q_SLOTS: void setImageModified(); void slotAutoSave(); void slotUndoStackCleanChanged(bool value); void slotConfigChanged(); private: /** * @brief try to clone the image. This method handles all the locking for you. If locking * has failed, no cloning happens * @return cloned document on success, null otherwise */ KisDocument *lockAndCloneForSaving(); QString exportErrorToUserMessage(KisImportExportFilter::ConversionStatus status, const QString &errorMessage); QString prettyPathOrUrl() const; bool openUrlInternal(const QUrl &url); void slotAutoSaveImpl(std::unique_ptr &&optionalClonedDocument); class Private; Private *const d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(KisDocument::OpenFlags) Q_DECLARE_METATYPE(KisDocument*) #endif diff --git a/libs/ui/KisMainWindow.cpp b/libs/ui/KisMainWindow.cpp index 8321c7c7bf..be04e2ee91 100644 --- a/libs/ui/KisMainWindow.cpp +++ b/libs/ui/KisMainWindow.cpp @@ -1,2663 +1,2663 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis Copyright (C) 2000-2006 David Faure Copyright (C) 2007, 2009 Thomas zander Copyright (C) 2010 Benjamin Port This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KisMainWindow.h" #include // qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_selection_manager.h" #include "kis_icon_utils.h" #include #include #include #include #include #include #include #include #include #include #include #include "KoDockFactoryBase.h" #include "KoDocumentInfoDlg.h" #include "KoDocumentInfo.h" #include "KoFileDialog.h" #include #include #include #include #include #include "KoToolDocker.h" #include "KoToolBoxDocker_p.h" #include #include #include #include #include #include #include #include "dialogs/kis_about_application.h" #include "dialogs/kis_delayed_save_dialog.h" #include "dialogs/kis_dlg_preferences.h" #include "kis_action.h" #include "kis_action_manager.h" #include "KisApplication.h" #include "kis_canvas2.h" #include "kis_canvas_controller.h" #include "kis_canvas_resource_provider.h" #include "kis_clipboard.h" #include "kis_config.h" #include "kis_config_notifier.h" #include "kis_custom_image_widget.h" #include #include "kis_group_layer.h" #include "kis_image_from_clipboard_widget.h" #include "kis_image.h" #include #include "KisImportExportManager.h" #include "kis_mainwindow_observer.h" #include "kis_memory_statistics_server.h" #include "kis_node.h" #include "KisOpenPane.h" #include "kis_paintop_box.h" #include "KisPart.h" #include "KisPrintJob.h" #include "KisResourceServerProvider.h" #include "kis_signal_compressor_with_param.h" #include "kis_statusbar.h" #include "KisView.h" #include "KisViewManager.h" #include "thememanager.h" #include "kis_animation_importer.h" #include "dialogs/kis_dlg_import_image_sequence.h" #include #include "KisWindowLayoutManager.h" #include #include "KisWelcomePageWidget.h" #include #include #include #ifdef Q_OS_WIN #include #endif class ToolDockerFactory : public KoDockFactoryBase { public: ToolDockerFactory() : KoDockFactoryBase() { } QString id() const override { return "sharedtooldocker"; } QDockWidget* createDockWidget() override { KoToolDocker* dockWidget = new KoToolDocker(); return dockWidget; } DockPosition defaultDockPosition() const override { return DockRight; } }; class Q_DECL_HIDDEN KisMainWindow::Private { public: Private(KisMainWindow *parent, QUuid id) : q(parent) , id(id) , dockWidgetMenu(new KActionMenu(i18nc("@action:inmenu", "&Dockers"), parent)) , windowMenu(new KActionMenu(i18nc("@action:inmenu", "&Window"), parent)) , documentMenu(new KActionMenu(i18nc("@action:inmenu", "New &View"), parent)) , workspaceMenu(new KActionMenu(i18nc("@action:inmenu", "Wor&kspace"), parent)) , welcomePage(new KisWelcomePageWidget(parent)) , widgetStack(new QStackedWidget(parent)) , mdiArea(new QMdiArea(parent)) , windowMapper(new QSignalMapper(parent)) , documentMapper(new QSignalMapper(parent)) { if (id.isNull()) this->id = QUuid::createUuid(); widgetStack->addWidget(welcomePage); widgetStack->addWidget(mdiArea); mdiArea->setTabsMovable(true); mdiArea->setActivationOrder(QMdiArea::ActivationHistoryOrder); } ~Private() { qDeleteAll(toolbarList); } KisMainWindow *q {0}; QUuid id; KisViewManager *viewManager {0}; QPointer activeView; QList toolbarList; bool firstTime {true}; bool windowSizeDirty {false}; bool readOnly {false}; KisAction *showDocumentInfo {0}; KisAction *saveAction {0}; KisAction *saveActionAs {0}; // KisAction *printAction; // KisAction *printActionPreview; // KisAction *exportPdf {0}; KisAction *importAnimation {0}; KisAction *closeAll {0}; // KisAction *reloadFile; KisAction *importFile {0}; KisAction *exportFile {0}; KisAction *undo {0}; KisAction *redo {0}; KisAction *newWindow {0}; KisAction *close {0}; KisAction *mdiCascade {0}; KisAction *mdiTile {0}; KisAction *mdiNextWindow {0}; KisAction *mdiPreviousWindow {0}; KisAction *toggleDockers {0}; KisAction *toggleDockerTitleBars {0}; KisAction *fullScreenMode {0}; KisAction *showSessionManager {0}; KisAction *expandingSpacers[2]; KActionMenu *dockWidgetMenu; KActionMenu *windowMenu; KActionMenu *documentMenu; KActionMenu *workspaceMenu; KHelpMenu *helpMenu {0}; KRecentFilesAction *recentFiles {0}; KoLegacyResourceModel *workspacemodel {0}; QScopedPointer undoActionsUpdateManager; QString lastExportLocation; QMap dockWidgetsMap; QByteArray dockerStateBeforeHiding; KoToolDocker *toolOptionsDocker {0}; QCloseEvent *deferredClosingEvent {0}; Digikam::ThemeManager *themeManager {0}; KisWelcomePageWidget *welcomePage {0}; QStackedWidget *widgetStack {0}; QMdiArea *mdiArea; QMdiSubWindow *activeSubWindow {0}; QSignalMapper *windowMapper; QSignalMapper *documentMapper; QByteArray lastExportedFormat; QScopedPointer > tabSwitchCompressor; QMutex savingEntryMutex; KConfigGroup windowStateConfig; QUuid workspaceBorrowedBy; KisSignalAutoConnectionsStore screenConnectionsStore; KisActionManager * actionManager() { return viewManager->actionManager(); } QTabBar* findTabBarHACK() { QObjectList objects = mdiArea->children(); Q_FOREACH (QObject *object, objects) { QTabBar *bar = qobject_cast(object); if (bar) { return bar; } } return 0; } }; KisMainWindow::KisMainWindow(QUuid uuid) : KXmlGuiWindow() , d(new Private(this, uuid)) { auto rserver = KisResourceServerProvider::instance()->workspaceServer(); QSharedPointer adapter(new KoResourceServerAdapter(rserver)); d->workspacemodel = new KoLegacyResourceModel(adapter, this); connect(d->workspacemodel, &KoLegacyResourceModel::afterResourcesLayoutReset, this, [&]() { updateWindowMenu(); }); d->viewManager = new KisViewManager(this, actionCollection()); KConfigGroup group( KSharedConfig::openConfig(), "theme"); d->themeManager = new Digikam::ThemeManager(group.readEntry("Theme", "Krita dark"), this); d->windowStateConfig = KSharedConfig::openConfig()->group("MainWindow"); setAcceptDrops(true); setStandardToolBarMenuEnabled(true); setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North); setDockNestingEnabled(true); qApp->setStartDragDistance(25); // 25 px is a distance that works well for Tablet and Mouse events #ifdef Q_OS_OSX setUnifiedTitleAndToolBarOnMac(true); #endif connect(this, SIGNAL(restoringDone()), this, SLOT(forceDockTabFonts())); connect(this, SIGNAL(themeChanged()), d->viewManager, SLOT(updateIcons())); connect(KisPart::instance(), SIGNAL(documentClosed(QString)), SLOT(updateWindowMenu())); connect(KisPart::instance(), SIGNAL(documentOpened(QString)), SLOT(updateWindowMenu())); connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), this, SLOT(configChanged())); actionCollection()->addAssociatedWidget(this); KoPluginLoader::instance()->load("Krita/ViewPlugin", "Type == 'Service' and ([X-Krita-Version] == 28)", KoPluginLoader::PluginsConfig(), d->viewManager, false); // Load the per-application plugins (Right now, only Python) We do this only once, when the first mainwindow is being created. KoPluginLoader::instance()->load("Krita/ApplicationPlugin", "Type == 'Service' and ([X-Krita-Version] == 28)", KoPluginLoader::PluginsConfig(), qApp, true); KoToolBoxFactory toolBoxFactory; QDockWidget *toolbox = createDockWidget(&toolBoxFactory); toolbox->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetClosable); KisConfig cfg(true); if (cfg.toolOptionsInDocker()) { ToolDockerFactory toolDockerFactory; d->toolOptionsDocker = qobject_cast(createDockWidget(&toolDockerFactory)); d->toolOptionsDocker->toggleViewAction()->setEnabled(true); } QMap dockwidgetActions; dockwidgetActions[toolbox->toggleViewAction()->text()] = toolbox->toggleViewAction(); Q_FOREACH (const QString & docker, KoDockRegistry::instance()->keys()) { KoDockFactoryBase *factory = KoDockRegistry::instance()->value(docker); QDockWidget *dw = createDockWidget(factory); dockwidgetActions[dw->toggleViewAction()->text()] = dw->toggleViewAction(); } if (d->toolOptionsDocker) { dockwidgetActions[d->toolOptionsDocker->toggleViewAction()->text()] = d->toolOptionsDocker->toggleViewAction(); } connect(KoToolManager::instance(), SIGNAL(toolOptionWidgetsChanged(KoCanvasController*,QList >)), this, SLOT(newOptionWidgets(KoCanvasController*,QList >))); Q_FOREACH (QString title, dockwidgetActions.keys()) { d->dockWidgetMenu->addAction(dockwidgetActions[title]); } Q_FOREACH (QDockWidget *wdg, dockWidgets()) { if ((wdg->features() & QDockWidget::DockWidgetClosable) == 0) { wdg->setVisible(true); } } Q_FOREACH (KoCanvasObserverBase* observer, canvasObservers()) { observer->setObservedCanvas(0); KisMainwindowObserver* mainwindowObserver = dynamic_cast(observer); if (mainwindowObserver) { mainwindowObserver->setViewManager(d->viewManager); } } d->mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); d->mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); d->mdiArea->setTabPosition(QTabWidget::North); d->mdiArea->setTabsClosable(true); // Tab close button override // Windows just has a black X, and Ubuntu has a dark x that is hard to read // just switch this icon out for all OSs so it is easier to see d->mdiArea->setStyleSheet("QTabBar::close-button { image: url(:/pics/broken-preset.png) }"); setCentralWidget(d->widgetStack); d->widgetStack->setCurrentIndex(0); connect(d->mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(subWindowActivated())); connect(d->windowMapper, SIGNAL(mapped(QWidget*)), this, SLOT(setActiveSubWindow(QWidget*))); connect(d->documentMapper, SIGNAL(mapped(QObject*)), this, SLOT(newView(QObject*))); createActions(); // the welcome screen needs to grab actions...so make sure this line goes after the createAction() so they exist d->welcomePage->setMainWindow(this); setAutoSaveSettings(d->windowStateConfig, false); subWindowActivated(); updateWindowMenu(); if (isHelpMenuEnabled() && !d->helpMenu) { // workaround for KHelpMenu (or rather KAboutData::applicationData()) internally // not using the Q*Application metadata ATM, which results e.g. in the bugreport wizard // not having the app version preset // fixed hopefully in KF5 5.22.0, patch pending QGuiApplication *app = qApp; KAboutData aboutData(app->applicationName(), app->applicationDisplayName(), app->applicationVersion()); aboutData.setOrganizationDomain(app->organizationDomain().toUtf8()); d->helpMenu = new KHelpMenu(this, aboutData, false); // workaround-less version: // d->helpMenu = new KHelpMenu(this, QString()/*unused*/, false); // The difference between using KActionCollection->addAction() is that // these actions do not get tied to the MainWindow. What does this all do? KActionCollection *actions = d->viewManager->actionCollection(); QAction *helpContentsAction = d->helpMenu->action(KHelpMenu::menuHelpContents); QAction *whatsThisAction = d->helpMenu->action(KHelpMenu::menuWhatsThis); QAction *reportBugAction = d->helpMenu->action(KHelpMenu::menuReportBug); QAction *switchLanguageAction = d->helpMenu->action(KHelpMenu::menuSwitchLanguage); QAction *aboutAppAction = d->helpMenu->action(KHelpMenu::menuAboutApp); QAction *aboutKdeAction = d->helpMenu->action(KHelpMenu::menuAboutKDE); if (helpContentsAction) { actions->addAction(helpContentsAction->objectName(), helpContentsAction); } if (whatsThisAction) { actions->addAction(whatsThisAction->objectName(), whatsThisAction); } if (reportBugAction) { actions->addAction(reportBugAction->objectName(), reportBugAction); } if (switchLanguageAction) { actions->addAction(switchLanguageAction->objectName(), switchLanguageAction); } if (aboutAppAction) { actions->addAction(aboutAppAction->objectName(), aboutAppAction); } if (aboutKdeAction) { actions->addAction(aboutKdeAction->objectName(), aboutKdeAction); } connect(d->helpMenu, SIGNAL(showAboutApplication()), SLOT(showAboutApplication())); } // KDE' libs 4''s help contents action is broken outside kde, for some reason... We can handle it just as easily ourselves QAction *helpAction = actionCollection()->action("help_contents"); helpAction->disconnect(); connect(helpAction, SIGNAL(triggered()), this, SLOT(showManual())); #if 0 //check for colliding shortcuts QSet existingShortcuts; Q_FOREACH (QAction* action, actionCollection()->actions()) { if(action->shortcut() == QKeySequence(0)) { continue; } dbgKrita << "shortcut " << action->text() << " " << action->shortcut(); Q_ASSERT(!existingShortcuts.contains(action->shortcut())); existingShortcuts.insert(action->shortcut()); } #endif configChanged(); // If we have customized the toolbars, load that first setLocalXMLFile(KoResourcePaths::locateLocal("data", "krita4.xmlgui")); setXMLFile(":/kxmlgui5/krita4.xmlgui"); guiFactory()->addClient(this); // Create and plug toolbar list for Settings menu QList toolbarList; Q_FOREACH (QWidget* it, guiFactory()->containers("ToolBar")) { KToolBar * toolBar = ::qobject_cast(it); if (toolBar) { if (toolBar->objectName() == "BrushesAndStuff") { toolBar->setEnabled(false); } KToggleAction* act = new KToggleAction(i18n("Show %1 Toolbar", toolBar->windowTitle()), this); actionCollection()->addAction(toolBar->objectName().toUtf8(), act); act->setCheckedState(KGuiItem(i18n("Hide %1 Toolbar", toolBar->windowTitle()))); connect(act, SIGNAL(toggled(bool)), this, SLOT(slotToolbarToggled(bool))); act->setChecked(!toolBar->isHidden()); toolbarList.append(act); } else { warnUI << "Toolbar list contains a " << it->metaObject()->className() << " which is not a toolbar!"; } } plugActionList("toolbarlist", toolbarList); d->toolbarList = toolbarList; applyToolBarLayout(); d->viewManager->updateGUI(); d->viewManager->updateIcons(); #ifdef Q_OS_WIN auto w = qApp->activeWindow(); if (w) QWindowsWindowFunctions::setHasBorderInFullScreen(w->windowHandle(), true); #endif QTimer::singleShot(1000, this, SLOT(checkSanity())); { using namespace std::placeholders; // For _1 placeholder std::function callback( std::bind(&KisMainWindow::switchTab, this, _1)); d->tabSwitchCompressor.reset( new KisSignalCompressorWithParam(500, callback, KisSignalCompressor::FIRST_INACTIVE)); } } KisMainWindow::~KisMainWindow() { // Q_FOREACH (QAction *ac, actionCollection()->actions()) { // QAction *action = qobject_cast(ac); // if (action) { // dbgKrita << "", "").replace("", "") // << "iconText=" << action->iconText().replace("&", "&") // << "shortcut=" << action->shortcut(QAction::ActiveShortcut).toString() // << "defaultShortcut=" << action->shortcut(QAction::DefaultShortcut).toString() // << "isCheckable=" << QString((action->isChecked() ? "true" : "false")) // << "statusTip=" << action->statusTip() // << "/>" ; // } // else { // dbgKrita << "Got a QAction:" << ac->objectName(); // } // } // The doc and view might still exist (this is the case when closing the window) KisPart::instance()->removeMainWindow(this); delete d->viewManager; delete d; } QUuid KisMainWindow::id() const { return d->id; } void KisMainWindow::addView(KisView *view) { if (d->activeView == view) return; if (d->activeView) { d->activeView->disconnect(this); } // register the newly created view in the input manager viewManager()->inputManager()->addTrackedCanvas(view->canvasBase()); showView(view); updateCaption(); emit restoringDone(); if (d->activeView) { connect(d->activeView, SIGNAL(titleModified(QString,bool)), SLOT(slotDocumentTitleModified())); connect(d->viewManager->statusBar(), SIGNAL(memoryStatusUpdated()), this, SLOT(updateCaption())); } } void KisMainWindow::notifyChildViewDestroyed(KisView *view) { viewManager()->inputManager()->removeTrackedCanvas(view->canvasBase()); if (view->canvasBase() == viewManager()->canvasBase()) { viewManager()->setCurrentView(0); } } void KisMainWindow::showView(KisView *imageView) { if (imageView && activeView() != imageView) { // XXX: find a better way to initialize this! imageView->setViewManager(d->viewManager); imageView->canvasBase()->setFavoriteResourceManager(d->viewManager->paintOpBox()->favoriteResourcesManager()); imageView->slotLoadingFinished(); QMdiSubWindow *subwin = d->mdiArea->addSubWindow(imageView); imageView->setSubWindow(subwin); subwin->setAttribute(Qt::WA_DeleteOnClose, true); connect(subwin, SIGNAL(destroyed()), SLOT(updateWindowMenu())); KisConfig cfg(true); subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); subwin->setWindowIcon(qApp->windowIcon()); /** * Hack alert! * * Here we explicitly request KoToolManager to emit all the tool * activation signals, to reinitialize the tool options docker. * * That is needed due to a design flaw we have in the * initialization procedure. The tool in the KoToolManager is * initialized in KisView::setViewManager() calls, which * happens early enough. During this call the tool manager * requests KoCanvasControllerWidget to emit the signal to * update the widgets in the tool docker. *But* at that moment * of time the view is not yet connected to the main window, * because it happens in KisViewManager::setCurrentView a bit * later. This fact makes the widgets updating signals be lost * and never reach the tool docker. * * So here we just explicitly call the tool activation stub. */ KoToolManager::instance()->initializeCurrentToolForCanvas(); if (d->mdiArea->subWindowList().size() == 1) { imageView->showMaximized(); } else { imageView->show(); } // No, no, no: do not try to call this _before_ the show() has // been called on the view; only when that has happened is the // opengl context active, and very bad things happen if we tell // the dockers to update themselves with a view if the opengl // context is not active. setActiveView(imageView); updateWindowMenu(); updateCaption(); } } void KisMainWindow::slotPreferences() { if (KisDlgPreferences::editPreferences()) { KisConfigNotifier::instance()->notifyConfigChanged(); KisConfigNotifier::instance()->notifyPixelGridModeChanged(); KisImageConfigNotifier::instance()->notifyConfigChanged(); // XXX: should this be changed for the views in other windows as well? Q_FOREACH (QPointer koview, KisPart::instance()->views()) { KisViewManager *view = qobject_cast(koview); if (view) { // Update the settings for all nodes -- they don't query // KisConfig directly because they need the settings during // compositing, and they don't connect to the config notifier // because nodes are not QObjects (because only one base class // can be a QObject). KisNode* node = dynamic_cast(view->image()->rootLayer().data()); node->updateSettings(); } } d->viewManager->showHideScrollbars(); } } void KisMainWindow::slotThemeChanged() { // save theme changes instantly KConfigGroup group( KSharedConfig::openConfig(), "theme"); group.writeEntry("Theme", d->themeManager->currentThemeName()); // reload action icons! Q_FOREACH (QAction *action, actionCollection()->actions()) { KisIconUtils::updateIcon(action); } emit themeChanged(); } void KisMainWindow::updateReloadFileAction(KisDocument *doc) { Q_UNUSED(doc); // d->reloadFile->setEnabled(doc && !doc->url().isEmpty()); } void KisMainWindow::setReadWrite(bool readwrite) { d->saveAction->setEnabled(readwrite); d->importFile->setEnabled(readwrite); d->readOnly = !readwrite; updateCaption(); } void KisMainWindow::addRecentURL(const QUrl &url) { // Add entry to recent documents list // (call coming from KisDocument because it must work with cmd line, template dlg, file/open, etc.) if (!url.isEmpty()) { bool ok = true; if (url.isLocalFile()) { QString path = url.adjusted(QUrl::StripTrailingSlash).toLocalFile(); const QStringList tmpDirs = KoResourcePaths::resourceDirs("tmp"); for (QStringList::ConstIterator it = tmpDirs.begin() ; ok && it != tmpDirs.end() ; ++it) { if (path.contains(*it)) { ok = false; // it's in the tmp resource } } const QStringList templateDirs = KoResourcePaths::findDirs("templates"); for (QStringList::ConstIterator it = templateDirs.begin() ; ok && it != templateDirs.end() ; ++it) { if (path.contains(*it)) { ok = false; // it's in the templates directory. break; } } } if (ok) { d->recentFiles->addUrl(url); } saveRecentFiles(); } } void KisMainWindow::saveRecentFiles() { // Save list of recent files KSharedConfigPtr config = KSharedConfig::openConfig(); d->recentFiles->saveEntries(config->group("RecentFiles")); config->sync(); // Tell all windows to reload their list, after saving // Doesn't work multi-process, but it's a start Q_FOREACH (KisMainWindow *mw, KisPart::instance()->mainWindows()) { if (mw != this) { mw->reloadRecentFileList(); } } } QList KisMainWindow::recentFilesUrls() { return d->recentFiles->urls(); } void KisMainWindow::clearRecentFiles() { d->recentFiles->clear(); } void KisMainWindow::reloadRecentFileList() { d->recentFiles->loadEntries(KSharedConfig::openConfig()->group("RecentFiles")); } void KisMainWindow::updateCaption() { if (!d->mdiArea->activeSubWindow()) { updateCaption(QString(), false); } else if (d->activeView && d->activeView->document() && d->activeView->image()){ KisDocument *doc = d->activeView->document(); QString caption(doc->caption()); if (d->readOnly) { caption += " [" + i18n("Write Protected") + "] "; } if (doc->isRecovered()) { caption += " [" + i18n("Recovered") + "] "; } // show the file size for the document KisMemoryStatisticsServer::Statistics m_fileSizeStats = KisMemoryStatisticsServer::instance()->fetchMemoryStatistics(d->activeView ? d->activeView->image() : 0); if (m_fileSizeStats.imageSize) { caption += QString(" (").append( KFormat().formatByteSize(m_fileSizeStats.imageSize)).append( ")"); } d->activeView->setWindowTitle(caption); d->activeView->setWindowModified(doc->isModified()); updateCaption(caption, doc->isModified()); if (!doc->url().fileName().isEmpty()) { d->saveAction->setToolTip(i18n("Save as %1", doc->url().fileName())); } else { d->saveAction->setToolTip(i18n("Save")); } } } void KisMainWindow::updateCaption(const QString & caption, bool mod) { dbgUI << "KisMainWindow::updateCaption(" << caption << "," << mod << ")"; QString versionString = KritaVersionWrapper::versionString(true); #if defined(KRITA_ALPHA) || defined (KRITA_BETA) || defined (KRITA_RC) setCaption(QString("%1: %2").arg(versionString).arg(caption), mod); return; #endif setCaption(caption, mod); } KisView *KisMainWindow::activeView() const { if (d->activeView) { return d->activeView; } return 0; } bool KisMainWindow::openDocument(const QUrl &url, OpenFlags flags) { if (!QFile(url.toLocalFile()).exists()) { if (!(flags & BatchMode)) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("The file %1 does not exist.", url.url())); } d->recentFiles->removeUrl(url); //remove the file from the recent-opened-file-list saveRecentFiles(); return false; } return openDocumentInternal(url, flags); } bool KisMainWindow::openDocumentInternal(const QUrl &url, OpenFlags flags) { if (!url.isLocalFile()) { qWarning() << "KisMainWindow::openDocumentInternal. Not a local file:" << url; return false; } KisDocument *newdoc = KisPart::instance()->createDocument(); if (flags & BatchMode) { newdoc->setFileBatchMode(true); } d->firstTime = true; connect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); connect(newdoc, SIGNAL(canceled(QString)), this, SLOT(slotLoadCanceled(QString))); KisDocument::OpenFlags openFlags = KisDocument::None; if (flags & RecoveryFile) { openFlags |= KisDocument::RecoveryFile; } bool openRet = !(flags & Import) ? newdoc->openUrl(url, openFlags) : newdoc->importDocument(url); if (!openRet) { delete newdoc; return false; } KisPart::instance()->addDocument(newdoc); updateReloadFileAction(newdoc); if (!QFileInfo(url.toLocalFile()).isWritable()) { setReadWrite(false); } return true; } void KisMainWindow::showDocument(KisDocument *document) { Q_FOREACH(QMdiSubWindow *subwindow, d->mdiArea->subWindowList()) { KisView *view = qobject_cast(subwindow->widget()); KIS_SAFE_ASSERT_RECOVER_NOOP(view); if (view) { if (view->document() == document) { setActiveSubWindow(subwindow); return; } } } addViewAndNotifyLoadingCompleted(document); } KisView* KisMainWindow::addViewAndNotifyLoadingCompleted(KisDocument *document) { showWelcomeScreen(false); // see workaround in function header KisView *view = KisPart::instance()->createView(document, resourceManager(), actionCollection(), this); addView(view); emit guiLoadingFinished(); return view; } QStringList KisMainWindow::showOpenFileDialog(bool isImporting) { KoFileDialog dialog(this, KoFileDialog::ImportFiles, "OpenDocument"); dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); dialog.setMimeTypeFilters(KisImportExportManager::supportedMimeTypes(KisImportExportManager::Import)); dialog.setCaption(isImporting ? i18n("Import Images") : i18n("Open Images")); return dialog.filenames(); } // Separate from openDocument to handle async loading (remote URLs) void KisMainWindow::slotLoadCompleted() { KisDocument *newdoc = qobject_cast(sender()); if (newdoc && newdoc->image()) { addViewAndNotifyLoadingCompleted(newdoc); disconnect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); disconnect(newdoc, SIGNAL(canceled(QString)), this, SLOT(slotLoadCanceled(QString))); emit loadCompleted(); } } void KisMainWindow::slotLoadCanceled(const QString & errMsg) { dbgUI << "KisMainWindow::slotLoadCanceled"; if (!errMsg.isEmpty()) // empty when canceled by user QMessageBox::critical(this, i18nc("@title:window", "Krita"), errMsg); // ... can't delete the document, it's the one who emitted the signal... KisDocument* doc = qobject_cast(sender()); Q_ASSERT(doc); disconnect(doc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); disconnect(doc, SIGNAL(canceled(QString)), this, SLOT(slotLoadCanceled(QString))); } void KisMainWindow::slotSaveCanceled(const QString &errMsg) { dbgUI << "KisMainWindow::slotSaveCanceled"; if (!errMsg.isEmpty()) // empty when canceled by user QMessageBox::critical(this, i18nc("@title:window", "Krita"), errMsg); slotSaveCompleted(); } void KisMainWindow::slotSaveCompleted() { dbgUI << "KisMainWindow::slotSaveCompleted"; KisDocument* doc = qobject_cast(sender()); Q_ASSERT(doc); disconnect(doc, SIGNAL(completed()), this, SLOT(slotSaveCompleted())); disconnect(doc, SIGNAL(canceled(QString)), this, SLOT(slotSaveCanceled(QString))); if (d->deferredClosingEvent) { KXmlGuiWindow::closeEvent(d->deferredClosingEvent); } } bool KisMainWindow::hackIsSaving() const { StdLockableWrapper wrapper(&d->savingEntryMutex); std::unique_lock> l(wrapper, std::try_to_lock); return !l.owns_lock(); } bool KisMainWindow::installBundle(const QString &fileName) const { QFileInfo from(fileName); QFileInfo to(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/bundles/" + from.fileName()); if (to.exists()) { QFile::remove(to.canonicalFilePath()); } return QFile::copy(fileName, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/bundles/" + from.fileName()); } bool KisMainWindow::saveDocument(KisDocument *document, bool saveas, bool isExporting) { if (!document) { return true; } /** * Make sure that we cannot enter this method twice! * * The lower level functions may call processEvents() so * double-entry is quite possible to achieve. Here we try to lock * the mutex, and if it is failed, just cancel saving. */ StdLockableWrapper wrapper(&d->savingEntryMutex); std::unique_lock> l(wrapper, std::try_to_lock); if (!l.owns_lock()) return false; // no busy wait for saving because it is dangerous! KisDelayedSaveDialog dlg(document->image(), KisDelayedSaveDialog::SaveDialog, 0, this); dlg.blockIfImageIsBusy(); if (dlg.result() == KisDelayedSaveDialog::Rejected) { return false; } else if (dlg.result() == KisDelayedSaveDialog::Ignored) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("You are saving a file while the image is " "still rendering. The saved file may be " "incomplete or corrupted.\n\n" "Please select a location where the original " "file will not be overridden!")); saveas = true; } if (document->isRecovered()) { saveas = true; } if (document->url().isEmpty()) { saveas = true; } connect(document, SIGNAL(completed()), this, SLOT(slotSaveCompleted())); connect(document, SIGNAL(canceled(QString)), this, SLOT(slotSaveCanceled(QString))); QByteArray nativeFormat = document->nativeFormatMimeType(); QByteArray oldMimeFormat = document->mimeType(); QUrl suggestedURL = document->url(); QStringList mimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export); mimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export); if (!mimeFilter.contains(oldMimeFormat)) { dbgUI << "KisMainWindow::saveDocument no export filter for" << oldMimeFormat; // --- don't setOutputMimeType in case the user cancels the Save As // dialog and then tries to just plain Save --- // suggest a different filename extension (yes, we fortunately don't all live in a world of magic :)) QString suggestedFilename = QFileInfo(suggestedURL.toLocalFile()).baseName(); if (!suggestedFilename.isEmpty()) { // ".kra" looks strange for a name suggestedFilename = suggestedFilename + "." + KisMimeDatabase::suffixesForMimeType(KIS_MIME_TYPE).first(); suggestedURL = suggestedURL.adjusted(QUrl::RemoveFilename); suggestedURL.setPath(suggestedURL.path() + suggestedFilename); } // force the user to choose outputMimeType saveas = true; } bool ret = false; if (document->url().isEmpty() || isExporting || saveas) { // if you're just File/Save As'ing to change filter options you // don't want to be reminded about overwriting files etc. bool justChangingFilterOptions = false; KoFileDialog dialog(this, KoFileDialog::SaveFile, "SaveAs"); dialog.setCaption(isExporting ? i18n("Exporting") : i18n("Saving As")); //qDebug() << ">>>>>" << isExporting << d->lastExportLocation << d->lastExportedFormat << QString::fromLatin1(document->mimeType()); if (isExporting && !d->lastExportLocation.isEmpty()) { // Use the location where we last exported to, if it's set, as the opening location for the file dialog QString proposedPath = QFileInfo(d->lastExportLocation).absolutePath(); // If the document doesn't have a filename yet, use the title QString proposedFileName = suggestedURL.isEmpty() ? document->documentInfo()->aboutInfo("title") : QFileInfo(suggestedURL.toLocalFile()).baseName(); // Use the last mimetype we exported to by default QString proposedMimeType = d->lastExportedFormat.isEmpty() ? "" : d->lastExportedFormat; QString proposedExtension = KisMimeDatabase::suffixesForMimeType(proposedMimeType).first().remove("*,"); // Set the default dir: this overrides the one loaded from the config file, since we're exporting and the lastExportLocation is not empty dialog.setDefaultDir(proposedPath + "/" + proposedFileName + "." + proposedExtension, true); dialog.setMimeTypeFilters(mimeFilter, proposedMimeType); } else { // Get the last used location for saving KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); QString proposedPath = group.readEntry("SaveAs", ""); // if that is empty, get the last used location for loading if (proposedPath.isEmpty()) { proposedPath = group.readEntry("OpenDocument", ""); } // If that is empty, too, use the Pictures location. if (proposedPath.isEmpty()) { proposedPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); } // But only use that if the suggestedUrl, that is, the document's own url is empty, otherwise // open the location where the document currently is. dialog.setDefaultDir(suggestedURL.isEmpty() ? proposedPath : suggestedURL.toLocalFile(), true); // If exporting, default to all supported file types if user is exporting QByteArray default_mime_type = ""; if (!isExporting) { // otherwise use the document's mimetype, or if that is empty, kra, which is the savest. default_mime_type = document->mimeType().isEmpty() ? nativeFormat : document->mimeType(); } dialog.setMimeTypeFilters(mimeFilter, QString::fromLatin1(default_mime_type)); } QUrl newURL = QUrl::fromUserInput(dialog.filename()); if (newURL.isLocalFile()) { QString fn = newURL.toLocalFile(); if (QFileInfo(fn).completeSuffix().isEmpty()) { fn.append(KisMimeDatabase::suffixesForMimeType(nativeFormat).first()); newURL = QUrl::fromLocalFile(fn); } } if (document->documentInfo()->aboutInfo("title") == i18n("Unnamed")) { QString fn = newURL.toLocalFile(); QFileInfo info(fn); document->documentInfo()->setAboutInfo("title", info.baseName()); } QByteArray outputFormat = nativeFormat; QString outputFormatString = KisMimeDatabase::mimeTypeForFile(newURL.toLocalFile(), false); outputFormat = outputFormatString.toLatin1(); if (!isExporting) { justChangingFilterOptions = (newURL == document->url()) && (outputFormat == document->mimeType()); } else { QString path = QFileInfo(d->lastExportLocation).absolutePath(); QString filename = QFileInfo(document->url().toLocalFile()).baseName(); justChangingFilterOptions = (QFileInfo(newURL.toLocalFile()).absolutePath() == path) && (QFileInfo(newURL.toLocalFile()).baseName() == filename) && (outputFormat == d->lastExportedFormat); } bool bOk = true; if (newURL.isEmpty()) { bOk = false; } if (bOk) { bool wantToSave = true; // don't change this line unless you know what you're doing :) if (!justChangingFilterOptions) { if (!document->isNativeFormat(outputFormat)) wantToSave = true; } if (wantToSave) { if (!isExporting) { // Save As ret = document->saveAs(newURL, outputFormat, true); if (ret) { dbgUI << "Successful Save As!"; KisPart::instance()->addRecentURLToAllMainWindows(newURL); setReadWrite(true); } else { dbgUI << "Failed Save As!"; } } else { // Export ret = document->exportDocument(newURL, outputFormat); if (ret) { d->lastExportLocation = newURL.toLocalFile(); d->lastExportedFormat = outputFormat; } } } // if (wantToSave) { else ret = false; } // if (bOk) { else ret = false; } else { // saving // We cannot "export" into the currently // opened document. We are not Gimp. KIS_ASSERT_RECOVER_NOOP(!isExporting); // be sure document has the correct outputMimeType! if (document->isModified()) { ret = document->save(true, 0); } if (!ret) { dbgUI << "Failed Save!"; } } updateReloadFileAction(document); updateCaption(); return ret; } void KisMainWindow::undo() { if (activeView()) { activeView()->document()->undoStack()->undo(); } } void KisMainWindow::redo() { if (activeView()) { activeView()->document()->undoStack()->redo(); } } void KisMainWindow::closeEvent(QCloseEvent *e) { if (!KisPart::instance()->closingSession()) { QAction *action= d->viewManager->actionCollection()->action("view_show_canvas_only"); if ((action) && (action->isChecked())) { action->setChecked(false); } // Save session when last window is closed if (KisPart::instance()->mainwindowCount() == 1) { bool closeAllowed = KisPart::instance()->closeSession(); if (!closeAllowed) { e->setAccepted(false); return; } } } d->mdiArea->closeAllSubWindows(); QList childrenList = d->mdiArea->subWindowList(); if (childrenList.isEmpty()) { d->deferredClosingEvent = e; saveWindowState(true); } else { e->setAccepted(false); } } void KisMainWindow::saveWindowSettings() { KSharedConfigPtr config = KSharedConfig::openConfig(); if (d->windowSizeDirty ) { dbgUI << "KisMainWindow::saveWindowSettings"; KConfigGroup group = d->windowStateConfig; KWindowConfig::saveWindowSize(windowHandle(), group); config->sync(); d->windowSizeDirty = false; } if (!d->activeView || d->activeView->document()) { // Save toolbar position into the config file of the app, under the doc's component name KConfigGroup group = d->windowStateConfig; saveMainWindowSettings(group); // Save collapsible state of dock widgets for (QMap::const_iterator i = d->dockWidgetsMap.constBegin(); i != d->dockWidgetsMap.constEnd(); ++i) { if (i.value()->widget()) { KConfigGroup dockGroup = group.group(QString("DockWidget ") + i.key()); dockGroup.writeEntry("Collapsed", i.value()->widget()->isHidden()); dockGroup.writeEntry("Locked", i.value()->property("Locked").toBool()); dockGroup.writeEntry("DockArea", (int) dockWidgetArea(i.value())); dockGroup.writeEntry("xPosition", (int) i.value()->widget()->x()); dockGroup.writeEntry("yPosition", (int) i.value()->widget()->y()); dockGroup.writeEntry("width", (int) i.value()->widget()->width()); dockGroup.writeEntry("height", (int) i.value()->widget()->height()); } } } KSharedConfig::openConfig()->sync(); resetAutoSaveSettings(); // Don't let KMainWindow override the good stuff we wrote down } void KisMainWindow::resizeEvent(QResizeEvent * e) { d->windowSizeDirty = true; KXmlGuiWindow::resizeEvent(e); } void KisMainWindow::setActiveView(KisView* view) { d->activeView = view; updateCaption(); if (d->undoActionsUpdateManager) { d->undoActionsUpdateManager->setCurrentDocument(view ? view->document() : 0); } d->viewManager->setCurrentView(view); KisWindowLayoutManager::instance()->activeDocumentChanged(view->document()); } void KisMainWindow::dragEnterEvent(QDragEnterEvent *event) { d->welcomePage->showDropAreaIndicator(true); if (event->mimeData()->hasUrls() || event->mimeData()->hasFormat("application/x-krita-node") || event->mimeData()->hasFormat("application/x-qt-image")) { event->accept(); } } void KisMainWindow::dropEvent(QDropEvent *event) { d->welcomePage->showDropAreaIndicator(false); if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() > 0) { Q_FOREACH (const QUrl &url, event->mimeData()->urls()) { if (url.toLocalFile().endsWith(".bundle")) { bool r = installBundle(url.toLocalFile()); if (!r) { qWarning() << "Could not install bundle" << url.toLocalFile(); } } else { openDocument(url, None); } } } } void KisMainWindow::dragMoveEvent(QDragMoveEvent * event) { QTabBar *tabBar = d->findTabBarHACK(); if (!tabBar && d->mdiArea->viewMode() == QMdiArea::TabbedView) { qWarning() << "WARNING!!! Cannot find QTabBar in the main window! Looks like Qt has changed behavior. Drag & Drop between multiple tabs might not work properly (tabs will not switch automatically)!"; } if (tabBar && tabBar->isVisible()) { QPoint pos = tabBar->mapFromGlobal(mapToGlobal(event->pos())); if (tabBar->rect().contains(pos)) { const int tabIndex = tabBar->tabAt(pos); if (tabIndex >= 0 && tabBar->currentIndex() != tabIndex) { d->tabSwitchCompressor->start(tabIndex); } } else if (d->tabSwitchCompressor->isActive()) { d->tabSwitchCompressor->stop(); } } } void KisMainWindow::dragLeaveEvent(QDragLeaveEvent * /*event*/) { d->welcomePage->showDropAreaIndicator(false); if (d->tabSwitchCompressor->isActive()) { d->tabSwitchCompressor->stop(); } } void KisMainWindow::switchTab(int index) { QTabBar *tabBar = d->findTabBarHACK(); if (!tabBar) return; tabBar->setCurrentIndex(index); } void KisMainWindow::showWelcomeScreen(bool show) { d->widgetStack->setCurrentIndex(!show); } void KisMainWindow::slotFileNew() { const QStringList mimeFilter = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Import); KisOpenPane *startupWidget = new KisOpenPane(this, mimeFilter, QStringLiteral("templates/")); startupWidget->setWindowModality(Qt::WindowModal); startupWidget->setWindowTitle(i18n("Create new document")); KisConfig cfg(true); int w = cfg.defImageWidth(); int h = cfg.defImageHeight(); const double resolution = cfg.defImageResolution(); const QString colorModel = cfg.defColorModel(); const QString colorDepth = cfg.defaultColorDepth(); const QString colorProfile = cfg.defColorProfile(); CustomDocumentWidgetItem item; item.widget = new KisCustomImageWidget(startupWidget, w, h, resolution, colorModel, colorDepth, colorProfile, i18n("Unnamed")); item.icon = "document-new"; startupWidget->addCustomDocumentWidget(item.widget, item.title, item.icon); QSize sz = KisClipboard::instance()->clipSize(); if (sz.isValid() && sz.width() != 0 && sz.height() != 0) { w = sz.width(); h = sz.height(); } item.widget = new KisImageFromClipboard(startupWidget, w, h, resolution, colorModel, colorDepth, colorProfile, i18n("Unnamed")); item.title = i18n("Create from Clipboard"); item.icon = "tab-new"; startupWidget->addCustomDocumentWidget(item.widget, item.title, item.icon); // calls deleteLater connect(startupWidget, SIGNAL(documentSelected(KisDocument*)), KisPart::instance(), SLOT(startCustomDocument(KisDocument*))); // calls deleteLater connect(startupWidget, SIGNAL(openTemplate(QUrl)), KisPart::instance(), SLOT(openTemplate(QUrl))); startupWidget->exec(); // Cancel calls deleteLater... } void KisMainWindow::slotImportFile() { dbgUI << "slotImportFile()"; slotFileOpen(true); } void KisMainWindow::slotFileOpen(bool isImporting) { QStringList urls = showOpenFileDialog(isImporting); if (urls.isEmpty()) return; Q_FOREACH (const QString& url, urls) { if (!url.isEmpty()) { OpenFlags flags = isImporting ? Import : None; bool res = openDocument(QUrl::fromLocalFile(url), flags); if (!res) { warnKrita << "Loading" << url << "failed"; } } } } void KisMainWindow::slotFileOpenRecent(const QUrl &url) { (void) openDocument(QUrl::fromLocalFile(url.toLocalFile()), None); } void KisMainWindow::slotFileSave() { if (saveDocument(d->activeView->document(), false, false)) { emit documentSaved(); } } void KisMainWindow::slotFileSaveAs() { if (saveDocument(d->activeView->document(), true, false)) { emit documentSaved(); } } void KisMainWindow::slotExportFile() { if (saveDocument(d->activeView->document(), true, true)) { emit documentSaved(); } } void KisMainWindow::slotShowSessionManager() { KisPart::instance()->showSessionManager(); } KoCanvasResourceProvider *KisMainWindow::resourceManager() const { return d->viewManager->resourceProvider()->resourceManager(); } int KisMainWindow::viewCount() const { return d->mdiArea->subWindowList().size(); } const KConfigGroup &KisMainWindow::windowStateConfig() const { return d->windowStateConfig; } void KisMainWindow::saveWindowState(bool restoreNormalState) { if (restoreNormalState) { QAction *showCanvasOnly = d->viewManager->actionCollection()->action("view_show_canvas_only"); if (showCanvasOnly && showCanvasOnly->isChecked()) { showCanvasOnly->setChecked(false); } d->windowStateConfig.writeEntry("ko_geometry", saveGeometry().toBase64()); d->windowStateConfig.writeEntry("State", saveState().toBase64()); if (!d->dockerStateBeforeHiding.isEmpty()) { restoreState(d->dockerStateBeforeHiding); } statusBar()->setVisible(true); menuBar()->setVisible(true); saveWindowSettings(); } else { saveMainWindowSettings(d->windowStateConfig); } } bool KisMainWindow::restoreWorkspaceState(const QByteArray &state) { QByteArray oldState = saveState(); // needed because otherwise the layout isn't correctly restored in some situations Q_FOREACH (QDockWidget *dock, dockWidgets()) { dock->toggleViewAction()->setEnabled(true); dock->hide(); } bool success = KXmlGuiWindow::restoreState(state); if (!success) { KXmlGuiWindow::restoreState(oldState); return false; } return success; } -bool KisMainWindow::restoreWorkspace(KisWorkspaceResource *workspace) +bool KisMainWindow::restoreWorkspace(KisWorkspaceResourceSP workspace) { bool success = restoreWorkspaceState(workspace->dockerState()); if (activeKisView()) { activeKisView()->resourceProvider()->notifyLoadingWorkspace(workspace); } return success; } QByteArray KisMainWindow::borrowWorkspace(KisMainWindow *other) { QByteArray currentWorkspace = saveState(); if (!d->workspaceBorrowedBy.isNull()) { if (other->id() == d->workspaceBorrowedBy) { // We're swapping our original workspace back d->workspaceBorrowedBy = QUuid(); return currentWorkspace; } else { // Get our original workspace back before swapping with a third window KisMainWindow *borrower = KisPart::instance()->windowById(d->workspaceBorrowedBy); if (borrower) { QByteArray originalLayout = borrower->borrowWorkspace(this); borrower->restoreWorkspaceState(currentWorkspace); d->workspaceBorrowedBy = other->id(); return originalLayout; } } } d->workspaceBorrowedBy = other->id(); return currentWorkspace; } void KisMainWindow::swapWorkspaces(KisMainWindow *a, KisMainWindow *b) { QByteArray workspaceA = a->borrowWorkspace(b); QByteArray workspaceB = b->borrowWorkspace(a); a->restoreWorkspaceState(workspaceB); b->restoreWorkspaceState(workspaceA); } KisViewManager *KisMainWindow::viewManager() const { return d->viewManager; } void KisMainWindow::slotDocumentInfo() { if (!d->activeView->document()) return; KoDocumentInfo *docInfo = d->activeView->document()->documentInfo(); if (!docInfo) return; KoDocumentInfoDlg *dlg = d->activeView->document()->createDocumentInfoDialog(this, docInfo); if (dlg->exec()) { if (dlg->isDocumentSaved()) { d->activeView->document()->setModified(false); } else { d->activeView->document()->setModified(true); } d->activeView->document()->setTitleModified(); } delete dlg; } bool KisMainWindow::slotFileCloseAll() { Q_FOREACH (QMdiSubWindow *subwin, d->mdiArea->subWindowList()) { if (subwin) { if(!subwin->close()) return false; } } updateCaption(); return true; } void KisMainWindow::slotFileQuit() { KisPart::instance()->closeSession(); } void KisMainWindow::slotFilePrint() { if (!activeView()) return; KisPrintJob *printJob = activeView()->createPrintJob(); if (printJob == 0) return; applyDefaultSettings(printJob->printer()); QPrintDialog *printDialog = activeView()->createPrintDialog( printJob, this ); if (printDialog && printDialog->exec() == QDialog::Accepted) { printJob->printer().setPageMargins(0.0, 0.0, 0.0, 0.0, QPrinter::Point); printJob->printer().setPaperSize(QSizeF(activeView()->image()->width() / (72.0 * activeView()->image()->xRes()), activeView()->image()->height()/ (72.0 * activeView()->image()->yRes())), QPrinter::Inch); printJob->startPrinting(KisPrintJob::DeleteWhenDone); } else { delete printJob; } delete printDialog; } void KisMainWindow::slotFilePrintPreview() { if (!activeView()) return; KisPrintJob *printJob = activeView()->createPrintJob(); if (printJob == 0) return; /* Sets the startPrinting() slot to be blocking. The Qt print-preview dialog requires the printing to be completely blocking and only return when the full document has been printed. By default the KisPrintingDialog is non-blocking and multithreading, setting blocking to true will allow it to be used in the preview dialog */ printJob->setProperty("blocking", true); QPrintPreviewDialog *preview = new QPrintPreviewDialog(&printJob->printer(), this); printJob->setParent(preview); // will take care of deleting the job connect(preview, SIGNAL(paintRequested(QPrinter*)), printJob, SLOT(startPrinting())); preview->exec(); delete preview; } KisPrintJob* KisMainWindow::exportToPdf(QString pdfFileName) { if (!activeView()) return 0; if (!activeView()->document()) return 0; KoPageLayout pageLayout; pageLayout.width = 0; pageLayout.height = 0; pageLayout.topMargin = 0; pageLayout.bottomMargin = 0; pageLayout.leftMargin = 0; pageLayout.rightMargin = 0; if (pdfFileName.isEmpty()) { KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); QString defaultDir = group.readEntry("SavePdfDialog"); if (defaultDir.isEmpty()) defaultDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); QUrl startUrl = QUrl::fromLocalFile(defaultDir); KisDocument* pDoc = d->activeView->document(); /** if document has a file name, take file name and replace extension with .pdf */ if (pDoc && pDoc->url().isValid()) { startUrl = pDoc->url(); QString fileName = startUrl.toLocalFile(); fileName = fileName.replace( QRegExp( "\\.\\w{2,5}$", Qt::CaseInsensitive ), ".pdf" ); startUrl = startUrl.adjusted(QUrl::RemoveFilename); startUrl.setPath(startUrl.path() + fileName ); } QPointer layoutDlg(new KoPageLayoutDialog(this, pageLayout)); layoutDlg->setWindowModality(Qt::WindowModal); if (layoutDlg->exec() != QDialog::Accepted || !layoutDlg) { delete layoutDlg; return 0; } pageLayout = layoutDlg->pageLayout(); delete layoutDlg; KoFileDialog dialog(this, KoFileDialog::SaveFile, "OpenDocument"); dialog.setCaption(i18n("Export as PDF")); dialog.setDefaultDir(startUrl.toLocalFile()); dialog.setMimeTypeFilters(QStringList() << "application/pdf"); QUrl url = QUrl::fromUserInput(dialog.filename()); pdfFileName = url.toLocalFile(); if (pdfFileName.isEmpty()) return 0; } KisPrintJob *printJob = activeView()->createPrintJob(); if (printJob == 0) return 0; if (isHidden()) { printJob->setProperty("noprogressdialog", true); } applyDefaultSettings(printJob->printer()); // TODO for remote files we have to first save locally and then upload. printJob->printer().setOutputFileName(pdfFileName); printJob->printer().setDocName(pdfFileName); printJob->printer().setColorMode(QPrinter::Color); if (pageLayout.format == KoPageFormat::CustomSize) { printJob->printer().setPaperSize(QSizeF(pageLayout.width, pageLayout.height), QPrinter::Millimeter); } else { printJob->printer().setPaperSize(KoPageFormat::printerPageSize(pageLayout.format)); } printJob->printer().setPageMargins(pageLayout.leftMargin, pageLayout.topMargin, pageLayout.rightMargin, pageLayout.bottomMargin, QPrinter::Millimeter); switch (pageLayout.orientation) { case KoPageFormat::Portrait: printJob->printer().setOrientation(QPrinter::Portrait); break; case KoPageFormat::Landscape: printJob->printer().setOrientation(QPrinter::Landscape); break; } //before printing check if the printer can handle printing if (!printJob->canPrint()) { QMessageBox::critical(this, i18nc("@title:window", "Krita"), i18n("Cannot export to the specified file")); } printJob->startPrinting(KisPrintJob::DeleteWhenDone); return printJob; } void KisMainWindow::importAnimation() { if (!activeView()) return; KisDocument *document = activeView()->document(); if (!document) return; KisDlgImportImageSequence dlg(this, document); if (dlg.exec() == QDialog::Accepted) { QStringList files = dlg.files(); int firstFrame = dlg.firstFrame(); int step = dlg.step(); KoUpdaterPtr updater = !document->fileBatchMode() ? viewManager()->createUnthreadedUpdater(i18n("Import frames")) : 0; KisAnimationImporter importer(document->image(), updater); KisImportExportFilter::ConversionStatus status = importer.import(files, firstFrame, step); if (status != KisImportExportFilter::OK && status != KisImportExportFilter::InternalError) { QString msg = KisImportExportFilter::conversionStatusString(status); if (!msg.isEmpty()) QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not finish import animation:\n%1", msg)); } activeView()->canvasBase()->refetchDataFromImage(); } } void KisMainWindow::slotConfigureToolbars() { saveWindowState(); KEditToolBar edit(factory(), this); connect(&edit, SIGNAL(newToolBarConfig()), this, SLOT(slotNewToolbarConfig())); (void) edit.exec(); applyToolBarLayout(); } void KisMainWindow::slotNewToolbarConfig() { applyMainWindowSettings(d->windowStateConfig); KXMLGUIFactory *factory = guiFactory(); Q_UNUSED(factory); // Check if there's an active view if (!d->activeView) return; plugActionList("toolbarlist", d->toolbarList); applyToolBarLayout(); } void KisMainWindow::slotToolbarToggled(bool toggle) { //dbgUI <<"KisMainWindow::slotToolbarToggled" << sender()->name() <<" toggle=" << true; // The action (sender) and the toolbar have the same name KToolBar * bar = toolBar(sender()->objectName()); if (bar) { if (toggle) { bar->show(); } else { bar->hide(); } if (d->activeView && d->activeView->document()) { saveWindowState(); } } else warnUI << "slotToolbarToggled : Toolbar " << sender()->objectName() << " not found!"; } void KisMainWindow::viewFullscreen(bool fullScreen) { KisConfig cfg(false); cfg.setFullscreenMode(fullScreen); if (fullScreen) { setWindowState(windowState() | Qt::WindowFullScreen); // set } else { setWindowState(windowState() & ~Qt::WindowFullScreen); // reset } } void KisMainWindow::setMaxRecentItems(uint _number) { d->recentFiles->setMaxItems(_number); } void KisMainWindow::slotReloadFile() { KisDocument* document = d->activeView->document(); if (!document || document->url().isEmpty()) return; if (document->isModified()) { bool ok = QMessageBox::question(this, i18nc("@title:window", "Krita"), i18n("You will lose all changes made since your last save\n" "Do you want to continue?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes; if (!ok) return; } QUrl url = document->url(); saveWindowSettings(); if (!document->reload()) { QMessageBox::critical(this, i18nc("@title:window", "Krita"), i18n("Error: Could not reload this document")); } return; } QDockWidget* KisMainWindow::createDockWidget(KoDockFactoryBase* factory) { QDockWidget* dockWidget = 0; bool lockAllDockers = KisConfig(true).readEntry("LockAllDockerPanels", false); if (!d->dockWidgetsMap.contains(factory->id())) { dockWidget = factory->createDockWidget(); // It is quite possible that a dock factory cannot create the dock; don't // do anything in that case. if (!dockWidget) { warnKrita << "Could not create docker for" << factory->id(); return 0; } dockWidget->setFont(KoDockRegistry::dockFont()); dockWidget->setObjectName(factory->id()); dockWidget->setParent(this); if (lockAllDockers) { if (dockWidget->titleBarWidget()) { dockWidget->titleBarWidget()->setVisible(false); } dockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures); } if (dockWidget->widget() && dockWidget->widget()->layout()) dockWidget->widget()->layout()->setContentsMargins(1, 1, 1, 1); Qt::DockWidgetArea side = Qt::RightDockWidgetArea; bool visible = true; switch (factory->defaultDockPosition()) { case KoDockFactoryBase::DockTornOff: dockWidget->setFloating(true); // position nicely? break; case KoDockFactoryBase::DockTop: side = Qt::TopDockWidgetArea; break; case KoDockFactoryBase::DockLeft: side = Qt::LeftDockWidgetArea; break; case KoDockFactoryBase::DockBottom: side = Qt::BottomDockWidgetArea; break; case KoDockFactoryBase::DockRight: side = Qt::RightDockWidgetArea; break; case KoDockFactoryBase::DockMinimized: default: side = Qt::RightDockWidgetArea; visible = false; } KConfigGroup group = d->windowStateConfig.group("DockWidget " + factory->id()); side = static_cast(group.readEntry("DockArea", static_cast(side))); if (side == Qt::NoDockWidgetArea) side = Qt::RightDockWidgetArea; addDockWidget(side, dockWidget); if (!visible) { dockWidget->hide(); } d->dockWidgetsMap.insert(factory->id(), dockWidget); } else { dockWidget = d->dockWidgetsMap[factory->id()]; } #ifdef Q_OS_OSX dockWidget->setAttribute(Qt::WA_MacSmallSize, true); #endif dockWidget->setFont(KoDockRegistry::dockFont()); connect(dockWidget, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(forceDockTabFonts())); return dockWidget; } void KisMainWindow::forceDockTabFonts() { Q_FOREACH (QObject *child, children()) { if (child->inherits("QTabBar")) { ((QTabBar *)child)->setFont(KoDockRegistry::dockFont()); } } } QList KisMainWindow::dockWidgets() const { return d->dockWidgetsMap.values(); } QDockWidget* KisMainWindow::dockWidget(const QString &id) { if (!d->dockWidgetsMap.contains(id)) return 0; return d->dockWidgetsMap[id]; } QList KisMainWindow::canvasObservers() const { QList observers; Q_FOREACH (QDockWidget *docker, dockWidgets()) { KoCanvasObserverBase *observer = dynamic_cast(docker); if (observer) { observers << observer; } else { warnKrita << docker << "is not a canvas observer"; } } return observers; } void KisMainWindow::toggleDockersVisibility(bool visible) { if (!visible) { d->dockerStateBeforeHiding = saveState(); Q_FOREACH (QObject* widget, children()) { if (widget->inherits("QDockWidget")) { QDockWidget* dw = static_cast(widget); if (dw->isVisible()) { dw->hide(); } } } } else { restoreState(d->dockerStateBeforeHiding); } } void KisMainWindow::slotDocumentTitleModified() { updateCaption(); updateReloadFileAction(d->activeView ? d->activeView->document() : 0); } void KisMainWindow::subWindowActivated() { bool enabled = (activeKisView() != 0); d->mdiCascade->setEnabled(enabled); d->mdiNextWindow->setEnabled(enabled); d->mdiPreviousWindow->setEnabled(enabled); d->mdiTile->setEnabled(enabled); d->close->setEnabled(enabled); d->closeAll->setEnabled(enabled); setActiveSubWindow(d->mdiArea->activeSubWindow()); Q_FOREACH (QToolBar *tb, toolBars()) { if (tb->objectName() == "BrushesAndStuff") { tb->setEnabled(enabled); } } /** * Qt has a weirdness, it has hardcoded shortcuts added to an action * in the window menu. We need to reset the shortcuts for that menu * to nothing, otherwise the shortcuts cannot be made configurable. * * See: https://bugs.kde.org/show_bug.cgi?id=352205 * https://bugs.kde.org/show_bug.cgi?id=375524 * https://bugs.kde.org/show_bug.cgi?id=398729 */ QMdiSubWindow *subWindow = d->mdiArea->currentSubWindow(); if (subWindow) { QMenu *menu = subWindow->systemMenu(); if (menu && menu->actions().size() == 8) { Q_FOREACH (QAction *action, menu->actions()) { action->setShortcut(QKeySequence()); } menu->actions().last()->deleteLater(); } } updateCaption(); d->actionManager()->updateGUI(); } void KisMainWindow::windowFocused() { /** * Notify selection manager so that it could update selection mask overlay */ if (viewManager() && viewManager()->selectionManager()) { viewManager()->selectionManager()->selectionChanged(); } KisPart *kisPart = KisPart::instance(); KisWindowLayoutManager *layoutManager = KisWindowLayoutManager::instance(); if (!layoutManager->primaryWorkspaceFollowsFocus()) return; QUuid primary = layoutManager->primaryWindowId(); if (primary.isNull()) return; if (d->id == primary) { if (!d->workspaceBorrowedBy.isNull()) { KisMainWindow *borrower = kisPart->windowById(d->workspaceBorrowedBy); if (!borrower) return; swapWorkspaces(this, borrower); } } else { if (d->workspaceBorrowedBy == primary) return; KisMainWindow *primaryWindow = kisPart->windowById(primary); if (!primaryWindow) return; swapWorkspaces(this, primaryWindow); } } void KisMainWindow::updateWindowMenu() { QMenu *menu = d->windowMenu->menu(); menu->clear(); menu->addAction(d->newWindow); menu->addAction(d->documentMenu); QMenu *docMenu = d->documentMenu->menu(); docMenu->clear(); Q_FOREACH (QPointer doc, KisPart::instance()->documents()) { if (doc) { QString title = doc->url().toDisplayString(); if (title.isEmpty() && doc->image()) { title = doc->image()->objectName(); } QAction *action = docMenu->addAction(title); action->setIcon(qApp->windowIcon()); connect(action, SIGNAL(triggered()), d->documentMapper, SLOT(map())); d->documentMapper->setMapping(action, doc); } } menu->addAction(d->workspaceMenu); QMenu *workspaceMenu = d->workspaceMenu->menu(); workspaceMenu->clear(); auto workspaces = KisResourceServerProvider::instance()->workspaceServer()->resources(); auto m_this = this; for (auto &w : workspaces) { auto action = workspaceMenu->addAction(w->name()); connect(action, &QAction::triggered, this, [=]() { m_this->restoreWorkspace(w); }); } workspaceMenu->addSeparator(); connect(workspaceMenu->addAction(i18nc("@action:inmenu", "&Import Workspace...")), &QAction::triggered, this, [&]() { QString extensions = d->workspacemodel->extensions(); QStringList mimeTypes; for(const QString &suffix : extensions.split(":")) { mimeTypes << KisMimeDatabase::mimeTypeForSuffix(suffix); } KoFileDialog dialog(0, KoFileDialog::OpenFile, "OpenDocument"); dialog.setMimeTypeFilters(mimeTypes); dialog.setCaption(i18nc("@title:window", "Choose File to Add")); QString filename = dialog.filename(); d->workspacemodel->importResourceFile(filename); }); connect(workspaceMenu->addAction(i18nc("@action:inmenu", "&New Workspace...")), &QAction::triggered, [=]() { QString name = QInputDialog::getText(this, i18nc("@title:window", "New Workspace..."), i18nc("@label:textbox", "Name:")); if (name.isEmpty()) return; auto rserver = KisResourceServerProvider::instance()->workspaceServer(); - KisWorkspaceResource* workspace = new KisWorkspaceResource(""); + KisWorkspaceResourceSP workspace(new KisWorkspaceResource("")); workspace->setDockerState(m_this->saveState()); d->viewManager->resourceProvider()->notifySavingWorkspace(workspace); workspace->setValid(true); QString saveLocation = rserver->saveLocation(); bool newName = false; if(name.isEmpty()) { newName = true; name = i18n("Workspace"); } QFileInfo fileInfo(saveLocation + name + workspace->defaultFileExtension()); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(saveLocation + name + QString("%1").arg(i) + workspace->defaultFileExtension()); i++; } workspace->setFilename(fileInfo.filePath()); if(newName) { name = i18n("Workspace %1", i); } workspace->setName(name); rserver->addResource(workspace); }); // TODO: What to do about delete? // workspaceMenu->addAction(i18nc("@action:inmenu", "&Delete Workspace...")); menu->addSeparator(); menu->addAction(d->close); menu->addAction(d->closeAll); if (d->mdiArea->viewMode() == QMdiArea::SubWindowView) { menu->addSeparator(); menu->addAction(d->mdiTile); menu->addAction(d->mdiCascade); } menu->addSeparator(); menu->addAction(d->mdiNextWindow); menu->addAction(d->mdiPreviousWindow); menu->addSeparator(); QList windows = d->mdiArea->subWindowList(); for (int i = 0; i < windows.size(); ++i) { QPointerchild = qobject_cast(windows.at(i)->widget()); if (child && child->document()) { QString text; if (i < 9) { text = i18n("&%1 %2", i + 1, child->document()->url().toDisplayString()); } else { text = i18n("%1 %2", i + 1, child->document()->url().toDisplayString()); } QAction *action = menu->addAction(text); action->setIcon(qApp->windowIcon()); action->setCheckable(true); action->setChecked(child == activeKisView()); connect(action, SIGNAL(triggered()), d->windowMapper, SLOT(map())); d->windowMapper->setMapping(action, windows.at(i)); } } bool showMdiArea = windows.count( ) > 0; if (!showMdiArea) { showWelcomeScreen(true); // see workaround in function in header // keep the recent file list updated when going back to welcome screen reloadRecentFileList(); d->welcomePage->populateRecentDocuments(); } // enable/disable the toolbox docker if there are no documents open Q_FOREACH (QObject* widget, children()) { if (widget->inherits("QDockWidget")) { QDockWidget* dw = static_cast(widget); if ( dw->objectName() == "ToolBox") { dw->setEnabled(showMdiArea); } } } updateCaption(); } void KisMainWindow::setActiveSubWindow(QWidget *window) { if (!window) return; QMdiSubWindow *subwin = qobject_cast(window); //dbgKrita << "setActiveSubWindow();" << subwin << d->activeSubWindow; if (subwin && subwin != d->activeSubWindow) { KisView *view = qobject_cast(subwin->widget()); //dbgKrita << "\t" << view << activeView(); if (view && view != activeView()) { d->mdiArea->setActiveSubWindow(subwin); setActiveView(view); } d->activeSubWindow = subwin; } updateWindowMenu(); d->actionManager()->updateGUI(); } void KisMainWindow::configChanged() { KisConfig cfg(true); QMdiArea::ViewMode viewMode = (QMdiArea::ViewMode)cfg.readEntry("mdi_viewmode", (int)QMdiArea::TabbedView); d->mdiArea->setViewMode(viewMode); Q_FOREACH (QMdiSubWindow *subwin, d->mdiArea->subWindowList()) { subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); /** * Dirty workaround for a bug in Qt (checked on Qt 5.6.1): * * If you make a window "Show on top" and then switch to the tabbed mode * the window will contiue to be painted in its initial "mid-screen" * position. It will persist here until you explicitly switch to its tab. */ if (viewMode == QMdiArea::TabbedView) { Qt::WindowFlags oldFlags = subwin->windowFlags(); Qt::WindowFlags flags = oldFlags; flags &= ~Qt::WindowStaysOnTopHint; flags &= ~Qt::WindowStaysOnBottomHint; if (flags != oldFlags) { subwin->setWindowFlags(flags); subwin->showMaximized(); } } } KConfigGroup group( KSharedConfig::openConfig(), "theme"); d->themeManager->setCurrentTheme(group.readEntry("Theme", "Krita dark")); d->actionManager()->updateGUI(); QBrush brush(cfg.getMDIBackgroundColor()); d->mdiArea->setBackground(brush); QString backgroundImage = cfg.getMDIBackgroundImage(); if (backgroundImage != "") { QImage image(backgroundImage); QBrush brush(image); d->mdiArea->setBackground(brush); } d->mdiArea->update(); } KisView* KisMainWindow::newView(QObject *document) { KisDocument *doc = qobject_cast(document); KisView *view = addViewAndNotifyLoadingCompleted(doc); d->actionManager()->updateGUI(); return view; } void KisMainWindow::newWindow() { KisMainWindow *mainWindow = KisPart::instance()->createMainWindow(); mainWindow->initializeGeometry(); mainWindow->show(); } void KisMainWindow::closeCurrentWindow() { if (d->mdiArea->currentSubWindow()) { d->mdiArea->currentSubWindow()->close(); d->actionManager()->updateGUI(); } } void KisMainWindow::checkSanity() { // print error if the lcms engine is not available if (!KoColorSpaceEngineRegistry::instance()->contains("icc")) { // need to wait 1 event since exiting here would not work. m_errorMessage = i18n("The Krita LittleCMS color management plugin is not installed. Krita will quit now."); m_dieOnError = true; QTimer::singleShot(0, this, SLOT(showErrorAndDie())); return; } KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); if (rserver->resources().isEmpty()) { m_errorMessage = i18n("Krita cannot find any brush presets! Krita will quit now."); m_dieOnError = true; QTimer::singleShot(0, this, SLOT(showErrorAndDie())); return; } } void KisMainWindow::showErrorAndDie() { QMessageBox::critical(0, i18nc("@title:window", "Installation error"), m_errorMessage); if (m_dieOnError) { exit(10); } } void KisMainWindow::showAboutApplication() { KisAboutApplication dlg(this); dlg.exec(); } QPointer KisMainWindow::activeKisView() { if (!d->mdiArea) return 0; QMdiSubWindow *activeSubWindow = d->mdiArea->activeSubWindow(); //dbgKrita << "activeKisView" << activeSubWindow; if (!activeSubWindow) return 0; return qobject_cast(activeSubWindow->widget()); } void KisMainWindow::newOptionWidgets(KoCanvasController *controller, const QList > &optionWidgetList) { KIS_ASSERT_RECOVER_NOOP(controller == KoToolManager::instance()->activeCanvasController()); bool isOurOwnView = false; Q_FOREACH (QPointer view, KisPart::instance()->views()) { if (view && view->canvasController() == controller) { isOurOwnView = view->mainWindow() == this; } } if (!isOurOwnView) return; Q_FOREACH (QWidget *w, optionWidgetList) { #ifdef Q_OS_OSX w->setAttribute(Qt::WA_MacSmallSize, true); #endif w->setFont(KoDockRegistry::dockFont()); } if (d->toolOptionsDocker) { d->toolOptionsDocker->setOptionWidgets(optionWidgetList); } else { d->viewManager->paintOpBox()->newOptionWidgets(optionWidgetList); } } void KisMainWindow::applyDefaultSettings(QPrinter &printer) { if (!d->activeView) return; QString title = d->activeView->document()->documentInfo()->aboutInfo("title"); if (title.isEmpty()) { QFileInfo info(d->activeView->document()->url().fileName()); title = info.baseName(); } if (title.isEmpty()) { // #139905 title = i18n("%1 unsaved document (%2)", qApp->applicationDisplayName(), QLocale().toString(QDate::currentDate(), QLocale::ShortFormat)); } printer.setDocName(title); } void KisMainWindow::createActions() { KisActionManager *actionManager = d->actionManager(); actionManager->createStandardAction(KStandardAction::New, this, SLOT(slotFileNew())); actionManager->createStandardAction(KStandardAction::Open, this, SLOT(slotFileOpen())); actionManager->createStandardAction(KStandardAction::Quit, this, SLOT(slotFileQuit())); actionManager->createStandardAction(KStandardAction::ConfigureToolbars, this, SLOT(slotConfigureToolbars())); d->fullScreenMode = actionManager->createStandardAction(KStandardAction::FullScreen, this, SLOT(viewFullscreen(bool))); d->recentFiles = KStandardAction::openRecent(this, SLOT(slotFileOpenRecent(QUrl)), actionCollection()); connect(d->recentFiles, SIGNAL(recentListCleared()), this, SLOT(saveRecentFiles())); KSharedConfigPtr configPtr = KSharedConfig::openConfig(); d->recentFiles->loadEntries(configPtr->group("RecentFiles")); d->saveAction = actionManager->createStandardAction(KStandardAction::Save, this, SLOT(slotFileSave())); d->saveAction->setActivationFlags(KisAction::ACTIVE_IMAGE); d->saveActionAs = actionManager->createStandardAction(KStandardAction::SaveAs, this, SLOT(slotFileSaveAs())); d->saveActionAs->setActivationFlags(KisAction::ACTIVE_IMAGE); // d->printAction = actionManager->createStandardAction(KStandardAction::Print, this, SLOT(slotFilePrint())); // d->printAction->setActivationFlags(KisAction::ACTIVE_IMAGE); // d->printActionPreview = actionManager->createStandardAction(KStandardAction::PrintPreview, this, SLOT(slotFilePrintPreview())); // d->printActionPreview->setActivationFlags(KisAction::ACTIVE_IMAGE); d->undo = actionManager->createStandardAction(KStandardAction::Undo, this, SLOT(undo())); d->undo->setActivationFlags(KisAction::ACTIVE_IMAGE); d->redo = actionManager->createStandardAction(KStandardAction::Redo, this, SLOT(redo())); d->redo->setActivationFlags(KisAction::ACTIVE_IMAGE); d->undoActionsUpdateManager.reset(new KisUndoActionsUpdateManager(d->undo, d->redo)); d->undoActionsUpdateManager->setCurrentDocument(d->activeView ? d->activeView->document() : 0); // d->exportPdf = actionManager->createAction("file_export_pdf"); // connect(d->exportPdf, SIGNAL(triggered()), this, SLOT(exportToPdf())); d->importAnimation = actionManager->createAction("file_import_animation"); connect(d->importAnimation, SIGNAL(triggered()), this, SLOT(importAnimation())); d->closeAll = actionManager->createAction("file_close_all"); connect(d->closeAll, SIGNAL(triggered()), this, SLOT(slotFileCloseAll())); // d->reloadFile = actionManager->createAction("file_reload_file"); // d->reloadFile->setActivationFlags(KisAction::CURRENT_IMAGE_MODIFIED); // connect(d->reloadFile, SIGNAL(triggered(bool)), this, SLOT(slotReloadFile())); d->importFile = actionManager->createAction("file_import_file"); connect(d->importFile, SIGNAL(triggered(bool)), this, SLOT(slotImportFile())); d->exportFile = actionManager->createAction("file_export_file"); connect(d->exportFile, SIGNAL(triggered(bool)), this, SLOT(slotExportFile())); /* The following entry opens the document information dialog. Since the action is named so it intends to show data this entry should not have a trailing ellipses (...). */ d->showDocumentInfo = actionManager->createAction("file_documentinfo"); connect(d->showDocumentInfo, SIGNAL(triggered(bool)), this, SLOT(slotDocumentInfo())); d->themeManager->setThemeMenuAction(new KActionMenu(i18nc("@action:inmenu", "&Themes"), this)); d->themeManager->registerThemeActions(actionCollection()); connect(d->themeManager, SIGNAL(signalThemeChanged()), this, SLOT(slotThemeChanged())); connect(d->themeManager, SIGNAL(signalThemeChanged()), d->welcomePage, SLOT(slotUpdateThemeColors())); d->toggleDockers = actionManager->createAction("view_toggledockers"); KisConfig(true).showDockers(true); d->toggleDockers->setChecked(true); connect(d->toggleDockers, SIGNAL(toggled(bool)), SLOT(toggleDockersVisibility(bool))); actionCollection()->addAction("settings_dockers_menu", d->dockWidgetMenu); actionCollection()->addAction("window", d->windowMenu); d->mdiCascade = actionManager->createAction("windows_cascade"); connect(d->mdiCascade, SIGNAL(triggered()), d->mdiArea, SLOT(cascadeSubWindows())); d->mdiTile = actionManager->createAction("windows_tile"); connect(d->mdiTile, SIGNAL(triggered()), d->mdiArea, SLOT(tileSubWindows())); d->mdiNextWindow = actionManager->createAction("windows_next"); connect(d->mdiNextWindow, SIGNAL(triggered()), d->mdiArea, SLOT(activateNextSubWindow())); d->mdiPreviousWindow = actionManager->createAction("windows_previous"); connect(d->mdiPreviousWindow, SIGNAL(triggered()), d->mdiArea, SLOT(activatePreviousSubWindow())); d->newWindow = actionManager->createAction("view_newwindow"); connect(d->newWindow, SIGNAL(triggered(bool)), this, SLOT(newWindow())); d->close = actionManager->createStandardAction(KStandardAction::Close, this, SLOT(closeCurrentWindow())); d->showSessionManager = actionManager->createAction("file_sessions"); connect(d->showSessionManager, SIGNAL(triggered(bool)), this, SLOT(slotShowSessionManager())); actionManager->createStandardAction(KStandardAction::Preferences, this, SLOT(slotPreferences())); for (int i = 0; i < 2; i++) { d->expandingSpacers[i] = new KisAction(i18n("Expanding Spacer")); d->expandingSpacers[i]->setDefaultWidget(new QWidget(this)); d->expandingSpacers[i]->defaultWidget()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); actionManager->addAction(QString("expanding_spacer_%1").arg(i), d->expandingSpacers[i]); } } void KisMainWindow::applyToolBarLayout() { const bool isPlastiqueStyle = style()->objectName() == "plastique"; Q_FOREACH (KToolBar *toolBar, toolBars()) { toolBar->layout()->setSpacing(4); if (isPlastiqueStyle) { toolBar->setContentsMargins(0, 0, 0, 2); } //Hide text for buttons with an icon in the toolbar Q_FOREACH (QAction *ac, toolBar->actions()){ if (ac->icon().pixmap(QSize(1,1)).isNull() == false){ ac->setPriority(QAction::LowPriority); }else { ac->setIcon(QIcon()); } } } } void KisMainWindow::initializeGeometry() { // if the user didn's specify the geometry on the command line (does anyone do that still?), // we first figure out some good default size and restore the x,y position. See bug 285804Z. KConfigGroup cfg = d->windowStateConfig; QByteArray geom = QByteArray::fromBase64(cfg.readEntry("ko_geometry", QByteArray())); if (!restoreGeometry(geom)) { const int scnum = QApplication::desktop()->screenNumber(parentWidget()); QRect desk = QApplication::desktop()->availableGeometry(scnum); // if the desktop is virtual then use virtual screen size if (QApplication::desktop()->isVirtualDesktop()) { desk = QApplication::desktop()->availableGeometry(QApplication::desktop()->screen(scnum)); } quint32 x = desk.x(); quint32 y = desk.y(); quint32 w = 0; quint32 h = 0; // Default size -- maximize on small screens, something useful on big screens const int deskWidth = desk.width(); if (deskWidth > 1024) { // a nice width, and slightly less than total available // height to compensate for the window decs w = (deskWidth / 3) * 2; h = (desk.height() / 3) * 2; } else { w = desk.width(); h = desk.height(); } x += (desk.width() - w) / 2; y += (desk.height() - h) / 2; move(x,y); setGeometry(geometry().x(), geometry().y(), w, h); } d->fullScreenMode->setChecked(isFullScreen()); } void KisMainWindow::showManual() { QDesktopServices::openUrl(QUrl("https://docs.krita.org")); } void KisMainWindow::moveEvent(QMoveEvent *e) { /** * For checking if the display number has changed or not we should always use * positional overload, not using QWidget overload. Otherwise we might get * inconsistency, because screenNumber(widget) can return -1, but screenNumber(pos) * will always return the nearest screen. */ const int oldScreen = qApp->desktop()->screenNumber(e->oldPos()); const int newScreen = qApp->desktop()->screenNumber(e->pos()); if (oldScreen != newScreen) { emit screenChanged(); } if (d->screenConnectionsStore.isEmpty() || oldScreen != newScreen) { d->screenConnectionsStore.clear(); QScreen *newScreenObject = 0; #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) newScreenObject = qApp->screenAt(e->pos()); #else // TODO: i'm not sure if this pointer already has a correct value // by the moment we get the event. It might not work on older // versions of Qt newScreenObject = qApp->primaryScreen(); #endif if (newScreenObject) { d->screenConnectionsStore.addConnection(newScreenObject, SIGNAL(physicalDotsPerInchChanged(qreal)), this, SIGNAL(screenChanged())); } } } #include diff --git a/libs/ui/KisMainWindow.h b/libs/ui/KisMainWindow.h index 46d993b3ec..bf91a9cd19 100644 --- a/libs/ui/KisMainWindow.h +++ b/libs/ui/KisMainWindow.h @@ -1,503 +1,504 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis Copyright (C) 2000-2004 David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_MAIN_WINDOW_H #define KIS_MAIN_WINDOW_H #include "kritaui_export.h" #include #include #include #include #include #include #include #include "KisView.h" +#include class QCloseEvent; class QMoveEvent; struct KoPageLayout; class KoCanvasResourceProvider; class KisDocument; class KisPrintJob; class KoDockFactoryBase; class QDockWidget; class KisView; class KisViewManager; class KoCanvasController; -class KisWorkspaceResource; + /** * @brief Main window for Krita * * This class is used to represent a main window within a Krita session. Each * main window contains a menubar and some toolbars, and potentially several * views of several canvases. * */ class KRITAUI_EXPORT KisMainWindow : public KXmlGuiWindow, public KoCanvasSupervisor { Q_OBJECT public: enum OpenFlag { None = 0, Import = 0x1, BatchMode = 0x2, RecoveryFile = 0x4 }; Q_DECLARE_FLAGS(OpenFlags, OpenFlag) public: /** * Constructor. * * Initializes a Calligra main window (with its basic GUI etc.). */ explicit KisMainWindow(QUuid id = QUuid()); /** * Destructor. */ ~KisMainWindow() override; QUuid id() const; /** * @brief showView shows the given view. Override this if you want to show * the view in a different way than by making it the central widget, for instance * as an QMdiSubWindow */ virtual void showView(KisView *view); /** * @returns the currently active view */ KisView *activeView() const; /** * Sets the maximum number of recent documents entries. */ void setMaxRecentItems(uint _number); /** * The document opened a URL -> store into recent documents list. */ void addRecentURL(const QUrl &url); /** * get list of URL strings for recent files */ QList recentFilesUrls(); /** * clears the list of the recent files */ void clearRecentFiles(); /** * Load the desired document and show it. * @param url the URL to open * * @return TRUE on success. */ bool openDocument(const QUrl &url, OpenFlags flags); /** * Activate a view containing the document in this window, creating one if needed. */ void showDocument(KisDocument *document); /** * Toggles between showing the welcome screen and the MDI area * * hack: There seems to be a bug that prevents events happening to the MDI area if it * isn't actively displayed (set in the widgetStack). This can cause things like the title bar * not to update correctly Before doing any actions related to opening or creating documents, * make sure to switch this first to make sure everything can communicate to the MDI area correctly */ void showWelcomeScreen(bool show); /** * Saves the document, asking for a filename if necessary. * * @param saveas if set to TRUE the user is always prompted for a filename * @param silent if set to TRUE rootDocument()->setTitleModified will not be called. * * @return TRUE on success, false on error or cancel * (don't display anything in this case, the error dialog box is also implemented here * but restore the original URL in slotFileSaveAs) */ bool saveDocument(KisDocument *document, bool saveas, bool isExporting); void setReadWrite(bool readwrite); /// Return the list of dock widgets belonging to this main window. QList dockWidgets() const; QDockWidget* dockWidget(const QString &id); QList canvasObservers() const override; KoCanvasResourceProvider *resourceManager() const; int viewCount() const; void saveWindowState(bool restoreNormalState =false); const KConfigGroup &windowStateConfig() const; /** * A wrapper around restoreState * @param state the saved state * @return TRUE on success */ - bool restoreWorkspace(KisWorkspaceResource *workspace); + bool restoreWorkspace(KisWorkspaceResourceSP workspace); bool restoreWorkspaceState(const QByteArray &state); static void swapWorkspaces(KisMainWindow *a, KisMainWindow *b); KisViewManager *viewManager() const; KisView *addViewAndNotifyLoadingCompleted(KisDocument *document); QStringList showOpenFileDialog(bool isImporting); /** * Shows if the main window is saving anything right now. If the * user presses Ctrl+W too fast, then the document can be close * before the saving is completed. I'm not sure if it is fixable * in any way without avoiding using porcessEvents() * everywhere (DK) * * Don't use it unless you have no option. */ bool hackIsSaving() const; /// Copy the given file into the bundle directory. bool installBundle(const QString &fileName) const; Q_SIGNALS: /** * This signal is emitted if the document has been saved successfully. */ void documentSaved(); /// This signal is emitted when this windows has finished loading of a /// document. The document may be opened in another window in the end. /// In this case, the signal means there is no link between the window /// and the document anymore. void loadCompleted(); /// This signal is emitted right after the docker states have been succefully restored from config void restoringDone(); /// This signal is emitted when the color theme changes void themeChanged(); /// This signal is emitted when the shortcut key configuration has changed void keyBindingsChanged(); void guiLoadingFinished(); /// emitted when the window is migrated among different screens void screenChanged(); public Q_SLOTS: /** * Slot for opening a new document. * * If the current document is empty, the new document replaces it. * If not, a new mainwindow will be opened for showing the document. */ void slotFileNew(); /** * Slot for opening a saved file. * * If the current document is empty, the opened document replaces it. * If not a new mainwindow will be opened for showing the opened file. */ void slotFileOpen(bool isImporting = false); /** * Slot for opening a file among the recently opened files. * * If the current document is empty, the opened document replaces it. * If not a new mainwindow will be opened for showing the opened file. */ void slotFileOpenRecent(const QUrl &); /** * @brief slotPreferences open the preferences dialog */ void slotPreferences(); /** * Update caption from document info - call when document info * (title in the about page) changes. */ void updateCaption(); /** * Saves the current document with the current name. */ void slotFileSave(); void slotShowSessionManager(); // XXX: disabled KisPrintJob* exportToPdf(QString pdfFileName = QString()); /** * Update the option widgets to the argument ones, removing the currently set widgets. */ void newOptionWidgets(KoCanvasController *controller, const QList > & optionWidgetList); KisView *newView(QObject *document); void notifyChildViewDestroyed(KisView *view); /// Set the active view, this will update the undo/redo actions void setActiveView(KisView *view); void subWindowActivated(); void windowFocused(); /** * Reloads the recent documents list. */ void reloadRecentFileList(); private Q_SLOTS: /** * Save the list of recent files. */ void saveRecentFiles(); void slotLoadCompleted(); void slotLoadCanceled(const QString &); void slotSaveCompleted(); void slotSaveCanceled(const QString &); void forceDockTabFonts(); /** * @internal */ void slotDocumentTitleModified(); /** * Prints the actual document. */ void slotFilePrint(); /** * Saves the current document with a new name. */ void slotFileSaveAs(); void slotFilePrintPreview(); void importAnimation(); /** * Show a dialog with author and document information. */ void slotDocumentInfo(); /** * Closes all open documents. */ bool slotFileCloseAll(); /** * @brief showAboutApplication show the about box */ virtual void showAboutApplication(); /** * Closes the mainwindow. */ void slotFileQuit(); /** * Configure toolbars. */ void slotConfigureToolbars(); /** * Post toolbar config. * (Plug action lists back in, etc.) */ void slotNewToolbarConfig(); /** * Shows or hides a toolbar */ void slotToolbarToggled(bool toggle); /** * Toggle full screen on/off. */ void viewFullscreen(bool fullScreen); /** * Reload file */ void slotReloadFile(); /** * File --> Import * * This will call slotFileOpen(). */ void slotImportFile(); /** * File --> Export * * This will call slotFileSaveAs(). */ void slotExportFile(); /** * Hide the dockers */ void toggleDockersVisibility(bool visible); /** * Handle theme changes from theme manager */ void slotThemeChanged(); void undo(); void redo(); void updateWindowMenu(); void setActiveSubWindow(QWidget *window); void configChanged(); void newWindow(); void closeCurrentWindow(); void checkSanity(); /// Quits Krita with error message from m_errorMessage. void showErrorAndDie(); void initializeGeometry(); void showManual(); void switchTab(int index); protected: void closeEvent(QCloseEvent * e) override; void resizeEvent(QResizeEvent * e) override; // QWidget overrides void dragEnterEvent(QDragEnterEvent * event) override; void dropEvent(QDropEvent * event) override; void dragMoveEvent(QDragMoveEvent * event) override; void dragLeaveEvent(QDragLeaveEvent * event) override; void moveEvent(QMoveEvent *e) override; private: /** * Add a the given view to the list of views of this mainwindow. * This is a private implementation. For public usage please use * newView() and addViewAndNotifyLoadingCompleted(). */ void addView(KisView *view); friend class KisPart; /** * Returns the dockwidget specified by the @p factory. If the dock widget doesn't exist yet it's created. * Add a "view_palette_action_menu" action to your view menu if you want to use closable dock widgets. * @param factory the factory used to create the dock widget if needed * @return the dock widget specified by @p factory (may be 0) */ QDockWidget* createDockWidget(KoDockFactoryBase* factory); bool openDocumentInternal(const QUrl &url, KisMainWindow::OpenFlags flags = 0); /** * Updates the window caption based on the document info and path. */ void updateCaption(const QString & caption, bool mod); void updateReloadFileAction(KisDocument *doc); void saveWindowSettings(); QPointer activeKisView(); void applyDefaultSettings(QPrinter &printer); void createActions(); void applyToolBarLayout(); QByteArray borrowWorkspace(KisMainWindow *borrower); private: /** * Struct used in the list created by createCustomDocumentWidgets() */ struct CustomDocumentWidgetItem { /// Pointer to the custom document widget QWidget *widget; /// title used in the sidebar. If left empty it will be displayed as "Custom Document" QString title; /// icon used in the sidebar. If left empty it will use the unknown icon QString icon; }; class Private; Private * const d; QString m_errorMessage; bool m_dieOnError; }; Q_DECLARE_OPERATORS_FOR_FLAGS(KisMainWindow::OpenFlags) #endif diff --git a/libs/ui/KisPaletteEditor.cpp b/libs/ui/KisPaletteEditor.cpp index 690894f4c4..71e020ed8e 100644 --- a/libs/ui/KisPaletteEditor.cpp +++ b/libs/ui/KisPaletteEditor.cpp @@ -1,663 +1,663 @@ /* * Copyright (c) 2018 Michael Zhou * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisPaletteEditor.h" struct KisPaletteEditor::PaletteInfo { QString name; QString filename; int columnCount; bool isGlobal; bool isReadOnly; QHash groups; }; struct KisPaletteEditor::Private { bool isGlobalModified {false}; bool isNameModified {false}; bool isFilenameModified {false}; bool isColumnCountModified {false}; QSet modifiedGroupNames; // key is original group name QSet newGroupNames; QSet keepColorGroups; QSet pathsToRemove; QString groupBeingRenamed; QPointer model; QPointer view; PaletteInfo modified; QPointer query; KoResourceServer *rServer; QPalette normalPalette; QPalette warnPalette; }; KisPaletteEditor::KisPaletteEditor(QObject *parent) : QObject(parent) , m_d(new Private) { m_d->rServer = KoResourceServerProvider::instance()->paletteServer(); m_d->warnPalette.setColor(QPalette::Text, Qt::red); } KisPaletteEditor::~KisPaletteEditor() { } void KisPaletteEditor::setPaletteModel(KisPaletteModel *model) { if (!model) { return; } m_d->model = model; slotPaletteChanged(); connect(model, SIGNAL(sigPaletteChanged()), SLOT(slotPaletteChanged())); connect(model, SIGNAL(sigPaletteModified()), SLOT(slotSetDocumentModified())); } void KisPaletteEditor::setView(KisViewManager *view) { m_d->view = view; } void KisPaletteEditor::addPalette() { if (!m_d->view) { return; } if (!m_d->view->document()) { return; } KoDialog dlg; QFormLayout layout; dlg.mainWidget()->setLayout(&layout); QLabel lbl(i18nc("Label for line edit to set a palette name.","Name")); QLineEdit le(i18nc("Default name for a new palette","New Palette")); layout.addRow(&lbl, &le); if (dlg.exec() != QDialog::Accepted) { return; } - KoColorSet *newColorSet = new KoColorSet(newPaletteFileName(false)); + KoColorSetSP newColorSet(new KoColorSet(newPaletteFileName(false))); newColorSet->setPaletteType(KoColorSet::KPL); newColorSet->setIsGlobal(false); newColorSet->setIsEditable(true); newColorSet->setValid(true); newColorSet->setName(le.text()); m_d->rServer->addResource(newColorSet); m_d->rServer->removeFromBlacklist(newColorSet); uploadPaletteList(); } void KisPaletteEditor::importPalette() { KoFileDialog dialog(Q_NULLPTR, KoFileDialog::OpenFile, "Open Palette"); dialog.setDefaultDir(QDir::homePath()); dialog.setMimeTypeFilters(QStringList() << "krita/x-colorset" << "application/x-gimp-color-palette"); QString filename = dialog.filename(); if (filename.isEmpty()) { return; } if (duplicateExistsFilename(filename, false)) { QMessageBox message; message.setWindowTitle(i18n("Can't Import Palette")); message.setText(i18n("Can't import palette: there's already imported with the same filename")); message.exec(); return; } - KoColorSet *colorSet = new KoColorSet(filename); + KoColorSetSP colorSet(new KoColorSet(filename)); colorSet->load(); QString name = filenameFromPath(colorSet->filename()); if (duplicateExistsFilename(name, false)) { colorSet->setFilename(newPaletteFileName(false)); } else { colorSet->setFilename(name); } colorSet->setIsGlobal(false); m_d->rServer->addResource(colorSet); m_d->rServer->removeFromBlacklist(colorSet); uploadPaletteList(); } -void KisPaletteEditor::removePalette(KoColorSet *cs) +void KisPaletteEditor::removePalette(KoColorSetSP cs) { if (!m_d->view) { return; } if (!m_d->view->document()) { return; } if (!cs || !cs->isEditable()) { return; } if (cs->isGlobal()) { m_d->rServer->removeResourceAndBlacklist(cs); QFile::remove(cs->filename()); return; } m_d->rServer->removeResourceFromServer(cs); uploadPaletteList(); } int KisPaletteEditor::rowNumberOfGroup(const QString &oriName) const { if (!m_d->modified.groups.contains(oriName)) { return 0; } return m_d->modified.groups[oriName].rowCount(); } bool KisPaletteEditor::duplicateExistsGroupName(const QString &name) const { if (name == m_d->groupBeingRenamed) { return false; } Q_FOREACH (const KisSwatchGroup &g, m_d->modified.groups.values()) { if (name == g.name()) { return true; } } return false; } bool KisPaletteEditor::duplicateExistsOriginalGroupName(const QString &name) const { return m_d->modified.groups.contains(name); } QString KisPaletteEditor::oldNameFromNewName(const QString &newName) const { Q_FOREACH (const QString &oldGroupName, m_d->modified.groups.keys()) { if (m_d->modified.groups[oldGroupName].name() == newName) { return oldGroupName; } } return QString(); } void KisPaletteEditor::rename(const QString &newName) { if (newName.isEmpty()) { return; } m_d->isNameModified = true; m_d->modified.name = newName; } void KisPaletteEditor::changeFilename(const QString &newName) { if (newName.isEmpty()) { return; } m_d->isFilenameModified = true; m_d->pathsToRemove.insert(m_d->modified.filename); if (m_d->modified.isGlobal) { m_d->modified.filename = m_d->rServer->saveLocation() + newName; } else { m_d->modified.filename = newName; } } void KisPaletteEditor::changeColCount(int newCount) { m_d->isColumnCountModified = true; m_d->modified.columnCount = newCount; } QString KisPaletteEditor::addGroup() { KoDialog dlg; m_d->query = &dlg; QVBoxLayout layout(&dlg); dlg.mainWidget()->setLayout(&layout); QLabel lblName(i18n("Name"), &dlg); layout.addWidget(&lblName); QLineEdit leName(&dlg); leName.setText(newGroupName()); connect(&leName, SIGNAL(textChanged(QString)), SLOT(slotGroupNameChanged(QString))); layout.addWidget(&leName); QLabel lblRowCount(i18n("Row count"), &dlg); layout.addWidget(&lblRowCount); QSpinBox spxRow(&dlg); spxRow.setValue(20); layout.addWidget(&spxRow); if (dlg.exec() != QDialog::Accepted) { return QString(); } if (duplicateExistsGroupName(leName.text())) { return QString(); } QString realName = leName.text(); QString name = realName; if (duplicateExistsOriginalGroupName(name)) { name = newGroupName(); } m_d->modified.groups[name] = KisSwatchGroup(); KisSwatchGroup &newGroup = m_d->modified.groups[name]; newGroup.setName(realName); m_d->newGroupNames.insert(name); newGroup.setRowCount(spxRow.value()); return realName; } bool KisPaletteEditor::removeGroup(const QString &name) { KoDialog window; window.setWindowTitle(i18nc("@title:window", "Removing Group")); QFormLayout editableItems(&window); QCheckBox chkKeep(&window); window.mainWidget()->setLayout(&editableItems); editableItems.addRow(i18nc("Shows up when deleting a swatch group", "Keep the Colors"), &chkKeep); if (window.exec() != KoDialog::Accepted) { return false; } m_d->modified.groups.remove(name); m_d->newGroupNames.remove(name); if (chkKeep.isChecked()) { m_d->keepColorGroups.insert(name); } return true; } QString KisPaletteEditor::renameGroup(const QString &oldName) { if (oldName.isEmpty() || oldName == KoColorSet::GLOBAL_GROUP_NAME) { return QString(); } KoDialog dlg; m_d->query = &dlg; m_d->groupBeingRenamed = m_d->modified.groups[oldName].name(); QFormLayout form(&dlg); dlg.mainWidget()->setLayout(&form); QLineEdit leNewName; connect(&leNewName, SIGNAL(textChanged(QString)), SLOT(slotGroupNameChanged(QString))); leNewName.setText(m_d->modified.groups[oldName].name()); form.addRow(i18nc("Renaming swatch group", "New name"), &leNewName); if (dlg.exec() != KoDialog::Accepted) { return QString(); } if (leNewName.text().isEmpty()) { return QString(); } if (duplicateExistsGroupName(leNewName.text())) { return QString(); } m_d->modified.groups[oldName].setName(leNewName.text()); m_d->modifiedGroupNames.insert(oldName); return leNewName.text(); } void KisPaletteEditor::slotGroupNameChanged(const QString &newName) { QLineEdit *leGroupName = qobject_cast(sender()); if (duplicateExistsGroupName(newName) || newName == QString()) { leGroupName->setPalette(m_d->warnPalette); if (m_d->query->button(KoDialog::Ok)) { m_d->query->button(KoDialog::Ok)->setEnabled(false); } return; } leGroupName->setPalette(m_d->normalPalette); if (m_d->query->button(KoDialog::Ok)) { m_d->query->button(KoDialog::Ok)->setEnabled(true); } } void KisPaletteEditor::changeGroupRowCount(const QString &name, int newRowCount) { if (!m_d->modified.groups.contains(name)) { return; } m_d->modified.groups[name].setRowCount(newRowCount); m_d->modifiedGroupNames.insert(name); } void KisPaletteEditor::setGlobal(bool isGlobal) { m_d->isGlobalModified = true; m_d->modified.isGlobal = isGlobal; } void KisPaletteEditor::setEntry(const KoColor &color, const QModelIndex &index) { Q_ASSERT(m_d->model); if (!m_d->model->colorSet()->isEditable()) { return; } if (!m_d->view) { return; } if (!m_d->view->document()) { return; } KisSwatch c = KisSwatch(color); c.setId(QString::number(m_d->model->colorSet()->colorCount() + 1)); c.setName(i18nc("Default name for a color swatch","Color %1", QString::number(m_d->model->colorSet()->colorCount()+1))); m_d->model->setEntry(c, index); } void KisPaletteEditor::slotSetDocumentModified() { m_d->view->document()->setModified(true); } void KisPaletteEditor::removeEntry(const QModelIndex &index) { Q_ASSERT(m_d->model); if (!m_d->model->colorSet()->isEditable()) { return; } if (!m_d->view) { return; } if (!m_d->view->document()) { return; } if (qvariant_cast(index.data(KisPaletteModel::IsGroupNameRole))) { removeGroup(qvariant_cast(index.data(KisPaletteModel::GroupNameRole))); updatePalette(); } else { m_d->model->removeEntry(index, false); } if (m_d->model->colorSet()->isGlobal()) { m_d->model->colorSet()->save(); return; } } void KisPaletteEditor::modifyEntry(const QModelIndex &index) { if (!m_d->model->colorSet()->isEditable()) { return; } if (!m_d->view) { return; } if (!m_d->view->document()) { return; } KoDialog dlg; dlg.setCaption(i18nc("@title:window", "Add a Color")); QFormLayout *editableItems = new QFormLayout(&dlg); dlg.mainWidget()->setLayout(editableItems); QString groupName = qvariant_cast(index.data(Qt::DisplayRole)); if (qvariant_cast(index.data(KisPaletteModel::IsGroupNameRole))) { renameGroup(groupName); updatePalette(); } else { QLineEdit *lnIDName = new QLineEdit(&dlg); QLineEdit *lnGroupName = new QLineEdit(&dlg); KisColorButton *bnColor = new KisColorButton(&dlg); QCheckBox *chkSpot = new QCheckBox(&dlg); chkSpot->setToolTip(i18nc("@info:tooltip", "A spot color is a color that the printer is able to print without mixing the paints it has available to it. The opposite is called a process color.")); KisSwatch entry = m_d->model->getEntry(index); editableItems->addRow(i18n("ID"), lnIDName); editableItems->addRow(i18nc("Name for a swatch group", "Swatch group name"), lnGroupName); editableItems->addRow(i18n("Color"), bnColor); editableItems->addRow(i18n("Spot"), chkSpot); lnGroupName->setText(entry.name()); lnIDName->setText(entry.id()); bnColor->setColor(entry.color()); chkSpot->setChecked(entry.spotColor()); if (dlg.exec() == KoDialog::Accepted) { entry.setName(lnGroupName->text()); entry.setId(lnIDName->text()); entry.setColor(bnColor->color()); entry.setSpotColor(chkSpot->isChecked()); m_d->model->setEntry(entry, index); } } } void KisPaletteEditor::addEntry(const KoColor &color) { Q_ASSERT(m_d->model); if (!m_d->view) { return; } if (!m_d->view->document()) { return; } if (!m_d->model->colorSet()->isEditable()) { return; } KoDialog window; window.setWindowTitle(i18nc("@title:window", "Add a new Colorset Entry")); QFormLayout editableItems(&window); window.mainWidget()->setLayout(&editableItems); QComboBox cmbGroups(&window); cmbGroups.addItems(m_d->model->colorSet()->getGroupNames()); QLineEdit lnIDName(&window); QLineEdit lnName(&window); KisColorButton bnColor(&window); QCheckBox chkSpot(&window); chkSpot.setToolTip(i18nc("@info:tooltip", "A spot color is a color that the printer is able to print without mixing the paints it has available to it. The opposite is called a process color.")); editableItems.addRow(i18n("Group"), &cmbGroups); editableItems.addRow(i18n("ID"), &lnIDName); editableItems.addRow(i18n("Name"), &lnName); editableItems.addRow(i18n("Color"), &bnColor); editableItems.addRow(i18nc("Spot color", "Spot"), &chkSpot); cmbGroups.setCurrentIndex(0); lnName.setText(i18nc("Default name for a color swatch","Color %1", QString::number(m_d->model->colorSet()->colorCount()+1))); lnIDName.setText(QString::number(m_d->model->colorSet()->colorCount() + 1)); bnColor.setColor(color); chkSpot.setChecked(false); if (window.exec() != KoDialog::Accepted) { return; } QString groupName = cmbGroups.currentText(); KisSwatch newEntry; newEntry.setColor(bnColor.color()); newEntry.setName(lnName.text()); newEntry.setId(lnIDName.text()); newEntry.setSpotColor(chkSpot.isChecked()); m_d->model->addEntry(newEntry, groupName); if (m_d->model->colorSet()->isGlobal()) { m_d->model->colorSet()->save(); return; } m_d->modifiedGroupNames.insert(groupName); m_d->modified.groups[groupName].addEntry(newEntry); } void KisPaletteEditor::updatePalette() { Q_ASSERT(m_d->model); Q_ASSERT(m_d->model->colorSet()); if (!m_d->model->colorSet()->isEditable()) { return; } if (!m_d->view) { return; } if (!m_d->view->document()) { return; } - KoColorSet *palette = m_d->model->colorSet(); + KoColorSetSP palette = m_d->model->colorSet(); PaletteInfo &modified = m_d->modified; if (m_d->isColumnCountModified) { palette->setColumnCount(modified.columnCount); } if (m_d->isNameModified) { palette->setName(modified.name); } if (m_d->isFilenameModified) { QString originalPath = palette->filename(); palette->setFilename(modified.filename); if (palette->isGlobal()) { if (!palette->save()) { palette->setFilename(newPaletteFileName(true)); palette->save(); } QFile::remove(originalPath); } } if (m_d->isGlobalModified) { palette->setIsGlobal(modified.isGlobal); if (modified.isGlobal) { setGlobal(); } else { setNonGlobal(); } } Q_FOREACH (const QString &groupName, palette->getGroupNames()) { if (!modified.groups.contains(groupName)) { m_d->model->removeGroup(groupName, m_d->keepColorGroups.contains(groupName)); } } m_d->keepColorGroups.clear(); Q_FOREACH (const QString &groupName, palette->getGroupNames()) { if (m_d->modifiedGroupNames.contains(groupName)) { m_d->model->setRowNumber(groupName, modified.groups[groupName].rowCount()); if (groupName != modified.groups[groupName].name()) { m_d->model->renameGroup(groupName, modified.groups[groupName].name()); modified.groups[modified.groups[groupName].name()] = modified.groups[groupName]; modified.groups.remove(groupName); } } } m_d->modifiedGroupNames.clear(); Q_FOREACH (const QString &newGroupName, m_d->newGroupNames) { m_d->model->addGroup(modified.groups[newGroupName]); } m_d->newGroupNames.clear(); if (m_d->model->colorSet()->isGlobal()) { m_d->model->colorSet()->save(); } } void KisPaletteEditor::slotPaletteChanged() { Q_ASSERT(m_d->model); if (!m_d->model->colorSet()) { return; } - KoColorSet *palette = m_d->model->colorSet(); + KoColorSetSP palette = m_d->model->colorSet(); m_d->modified.groups.clear(); m_d->keepColorGroups.clear(); m_d->newGroupNames.clear(); m_d->modifiedGroupNames.clear(); m_d->modified.name = palette->name(); m_d->modified.filename = palette->filename(); m_d->modified.columnCount = palette->columnCount(); m_d->modified.isGlobal = palette->isGlobal(); m_d->modified.isReadOnly = !palette->isEditable(); Q_FOREACH (const QString &groupName, palette->getGroupNames()) { KisSwatchGroup *cs = palette->getGroup(groupName); m_d->modified.groups[groupName] = KisSwatchGroup(*cs); } } void KisPaletteEditor::setGlobal() { Q_ASSERT(m_d->model); if (!m_d->view) { return; } if (!m_d->view->document()) { return; } if (!m_d->model->colorSet()) { return; } - KoColorSet *colorSet = m_d->model->colorSet(); + KoColorSetSP colorSet = m_d->model->colorSet(); QString saveLocation = m_d->rServer->saveLocation(); QString name = filenameFromPath(colorSet->filename()); QFileInfo fileInfo(saveLocation + name); colorSet->setFilename(fileInfo.filePath()); colorSet->setIsGlobal(true); m_d->rServer->removeFromBlacklist(colorSet); if (!colorSet->save()) { QMessageBox message; message.setWindowTitle(i18n("Saving palette failed")); message.setText(i18n("Failed to save global palette file. Please set it to non-global, or you will lose the file when you close Krita")); message.exec(); } uploadPaletteList(); } bool KisPaletteEditor::duplicateExistsFilename(const QString &filename, bool global) const { QString prefix; if (global) { prefix = m_d->rServer->saveLocation(); } - Q_FOREACH (const KoResource *r, KoResourceServerProvider::instance()->paletteServer()->resources()) { + Q_FOREACH (const KoResourceSP r, KoResourceServerProvider::instance()->paletteServer()->resources()) { if (r->filename() == prefix + filename && r != m_d->model->colorSet()) { return true; } } return false; } QString KisPaletteEditor::relativePathFromSaveLocation() const { return filenameFromPath(m_d->modified.filename); } void KisPaletteEditor::setNonGlobal() { Q_ASSERT(m_d->model); if (!m_d->view) { return; } if (!m_d->view->document()) { return; } if (!m_d->model->colorSet()) { return; } - KoColorSet *colorSet = m_d->model->colorSet(); + KoColorSetSP colorSet = m_d->model->colorSet(); QString name = filenameFromPath(colorSet->filename()); QFile::remove(colorSet->filename()); if (duplicateExistsFilename(name, false)) { colorSet->setFilename(newPaletteFileName(false)); } else { colorSet->setFilename(name); } colorSet->setIsGlobal(false); uploadPaletteList(); } QString KisPaletteEditor::newPaletteFileName(bool isGlobal) { QSet nameSet; - Q_FOREACH (const KoResource *r, m_d->rServer->resources()) { + Q_FOREACH (const KoResourceSP r, m_d->rServer->resources()) { nameSet.insert(r->filename()); } KoColorSet tmpColorSet; QString result = "new_palette_"; if (isGlobal) { result = m_d->rServer->saveLocation() + result; } int i = 0; while (nameSet.contains(result + QString::number(i) + tmpColorSet.defaultFileExtension())) { i++; } result = result + QString::number(i) + tmpColorSet.defaultFileExtension(); return result; } QString KisPaletteEditor::newGroupName() const { int i = 1; QString groupname = i18nc("Default new group name", "New Group %1", QString::number(i)); while (m_d->modified.groups.contains(groupname)) { i++; groupname = i18nc("Default new group name", "New Group %1", QString::number(i)); } return groupname; } void KisPaletteEditor::uploadPaletteList() const { - QList list; - Q_FOREACH (KoResource * paletteResource, m_d->rServer->resources()) { - KoColorSet *palette = static_cast(paletteResource); + QList list; + Q_FOREACH (KoResourceSP paletteResource, m_d->rServer->resources()) { + KoColorSetSP palette = paletteResource.staticCast(); Q_ASSERT(palette); if (!palette->isGlobal()) { list.append(palette); } } m_d->view->document()->setPaletteList(list); } QString KisPaletteEditor::filenameFromPath(const QString &path) const { return QDir::fromNativeSeparators(path).section('/', -1, -1); } diff --git a/libs/ui/KisPaletteEditor.h b/libs/ui/KisPaletteEditor.h index abda68e712..7596294f89 100644 --- a/libs/ui/KisPaletteEditor.h +++ b/libs/ui/KisPaletteEditor.h @@ -1,148 +1,148 @@ /* * Copyright (c) 2018 Michael Zhou * * 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 KISPALETTEMANAGER_H #define KISPALETTEMANAGER_H #include #include #include #include class KoColorSet; class KisPaletteModel; class KisViewManager; class KisSwatchGroup; class KisViewManager; /** * @brief The PaletteEditor class * this class manipulates a KisPaletteModel using GUI elements and communicate * with KisDocument * * Changes made in this class won't be done to the palette if the palette is * read only (not editable, isEditable() == false) */ class KRITAUI_EXPORT KisPaletteEditor : public QObject { Q_OBJECT public: struct PaletteInfo; public: explicit KisPaletteEditor(QObject *parent = Q_NULLPTR); ~KisPaletteEditor(); void setPaletteModel(KisPaletteModel *model); void setView(KisViewManager *view); void addPalette(); void importPalette(); - void removePalette(KoColorSet *); + void removePalette(KoColorSetSP ); /** * @brief rowNumberOfGroup * @param oriName the original name of a group at the creation of the instance * @return newest row number of the group */ int rowNumberOfGroup(const QString &oriName) const; /** * @brief oldNameFromNewName * @param newName the current name of a group * @return the name of the group at the creation of the instance */ QString oldNameFromNewName(const QString &newName) const; /** * @brief duplicateExistsFilename * @param name * @param global if this filename is going to be used for a global palette * @return true if the a palette in the resource system that has filename * name already exists else false */ bool duplicateExistsFilename(const QString &filename, bool global) const; QString relativePathFromSaveLocation() const; void rename(const QString &newName); void changeFilename(const QString &newName); void changeColCount(int); /** * @brief addGroup * @param name original group name * @param rowNumber * @return new group's name if change accpeted, empty string if cancelled */ QString addGroup(); /** * @brief removeGroup * @param name original group name * @return true if change accepted, false if cancelled */ bool removeGroup(const QString &name); /** * @brief renameGroup * @param oldName * @return new name if change accpeted, empty string if cancelled */ QString renameGroup(const QString &oldName); void changeGroupRowCount(const QString &name, int newRowCount); void setGlobal(bool); void setReadOnly(bool); void setEntry(const KoColor &color, const QModelIndex &index); void removeEntry(const QModelIndex &index); void modifyEntry(const QModelIndex &index); void addEntry(const KoColor &color); bool isModified() const; /** * @brief getModifiedGroup * @param originalName name of the group at the creation of the instance * @return the modified group */ const KisSwatchGroup &getModifiedGroup(const QString &originalName) const; /** * @brief updatePalette * MUST be called to make the changes into the resource server */ void updatePalette(); private Q_SLOTS: void slotGroupNameChanged(const QString &newName); void slotPaletteChanged(); void slotSetDocumentModified(); private: QString newPaletteFileName(bool isGlobal); QString newGroupName() const; void setNonGlobal(); void setGlobal(); bool duplicateExistsGroupName(const QString &name) const; bool duplicateExistsOriginalGroupName(const QString &name) const; void uploadPaletteList() const; QString filenameFromPath(const QString &path) const; private: struct Private; QScopedPointer m_d; }; #endif // KISPALETTEMANAGER_H diff --git a/libs/ui/KisPart.cpp b/libs/ui/KisPart.cpp index 5355417af2..b0c569cf13 100644 --- a/libs/ui/KisPart.cpp +++ b/libs/ui/KisPart.cpp @@ -1,567 +1,567 @@ /* This file is part of the KDE project * Copyright (C) 1998-1999 Torben Weis * Copyright (C) 2000-2005 David Faure * Copyright (C) 2007-2008 Thorsten Zachmann * Copyright (C) 2010-2012 Boudewijn Rempt * Copyright (C) 2011 Inge Wallin * Copyright (C) 2015 Michael Abrahams * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KisPart.h" #include "KoProgressProxy.h" #include #include #include #include #include #include #include #include #include "KisApplication.h" #include "KisMainWindow.h" #include "KisDocument.h" #include "KisView.h" #include "KisViewManager.h" #include "KisImportExportManager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_config.h" #include "kis_shape_controller.h" #include "KisResourceServerProvider.h" #include "kis_animation_cache_populator.h" #include "kis_idle_watcher.h" #include "kis_image.h" #include "KisOpenPane.h" #include "kis_color_manager.h" #include "kis_action.h" #include "kis_action_registry.h" #include "KisSessionResource.h" Q_GLOBAL_STATIC(KisPart, s_instance) class Q_DECL_HIDDEN KisPart::Private { public: Private(KisPart *_part) : part(_part) , idleWatcher(2500) , animationCachePopulator(_part) { } ~Private() { } KisPart *part; QList > views; QList > mainWindows; QList > documents; KActionCollection *actionCollection{0}; KisIdleWatcher idleWatcher; KisAnimationCachePopulator animationCachePopulator; - KisSessionResource *currentSession = nullptr; + KisSessionResourceSP currentSession; bool closingSession{false}; QScopedPointer sessionManager; bool queryCloseDocument(KisDocument *document) { Q_FOREACH(auto view, views) { if (view && view->isVisible() && view->document() == document) { return view->queryClose(); } } return true; } }; KisPart* KisPart::instance() { return s_instance; } KisPart::KisPart() : d(new Private(this)) { // Preload all the resources in the background Q_UNUSED(KoResourceServerProvider::instance()); Q_UNUSED(KisResourceServerProvider::instance()); Q_UNUSED(KisColorManager::instance()); connect(this, SIGNAL(documentOpened(QString)), this, SLOT(updateIdleWatcherConnections())); connect(this, SIGNAL(documentClosed(QString)), this, SLOT(updateIdleWatcherConnections())); connect(KisActionRegistry::instance(), SIGNAL(shortcutsUpdated()), this, SLOT(updateShortcuts())); connect(&d->idleWatcher, SIGNAL(startedIdleMode()), &d->animationCachePopulator, SLOT(slotRequestRegeneration())); d->animationCachePopulator.slotRequestRegeneration(); } KisPart::~KisPart() { while (!d->documents.isEmpty()) { delete d->documents.takeFirst(); } while (!d->views.isEmpty()) { delete d->views.takeFirst(); } while (!d->mainWindows.isEmpty()) { delete d->mainWindows.takeFirst(); } delete d; } void KisPart::updateIdleWatcherConnections() { QVector images; Q_FOREACH (QPointer document, documents()) { if (document->image()) { images << document->image(); } } d->idleWatcher.setTrackedImages(images); } void KisPart::addDocument(KisDocument *document) { //dbgUI << "Adding document to part list" << document; Q_ASSERT(document); if (!d->documents.contains(document)) { d->documents.append(document); emit documentOpened('/'+objectName()); emit sigDocumentAdded(document); connect(document, SIGNAL(sigSavingFinished()), SLOT(slotDocumentSaved())); } } QList > KisPart::documents() const { return d->documents; } KisDocument *KisPart::createDocument() const { KisDocument *doc = new KisDocument(); return doc; } int KisPart::documentCount() const { return d->documents.size(); } void KisPart::removeDocument(KisDocument *document) { d->documents.removeAll(document); emit documentClosed('/'+objectName()); emit sigDocumentRemoved(document->url().toLocalFile()); document->deleteLater(); } KisMainWindow *KisPart::createMainWindow(QUuid id) { KisMainWindow *mw = new KisMainWindow(id); dbgUI <<"mainWindow" << (void*)mw << "added to view" << this; d->mainWindows.append(mw); emit sigWindowAdded(mw); return mw; } KisView *KisPart::createView(KisDocument *document, KoCanvasResourceProvider *resourceManager, KActionCollection *actionCollection, QWidget *parent) { // If creating the canvas fails, record this and disable OpenGL next time KisConfig cfg(false); KConfigGroup grp( KSharedConfig::openConfig(), "crashprevention"); if (grp.readEntry("CreatingCanvas", false)) { cfg.setUseOpenGL(false); } if (cfg.canvasState() == "OPENGL_FAILED") { cfg.setUseOpenGL(false); } grp.writeEntry("CreatingCanvas", true); grp.sync(); QApplication::setOverrideCursor(Qt::WaitCursor); KisView *view = new KisView(document, resourceManager, actionCollection, parent); QApplication::restoreOverrideCursor(); // Record successful canvas creation grp.writeEntry("CreatingCanvas", false); grp.sync(); addView(view); return view; } void KisPart::addView(KisView *view) { if (!view) return; if (!d->views.contains(view)) { d->views.append(view); } emit sigViewAdded(view); } void KisPart::removeView(KisView *view) { if (!view) return; /** * HACK ALERT: we check here explicitly if the document (or main * window), is saving the stuff. If we close the * document *before* the saving is completed, a crash * will happen. */ KIS_ASSERT_RECOVER_RETURN(!view->mainWindow()->hackIsSaving()); emit sigViewRemoved(view); QPointer doc = view->document(); d->views.removeAll(view); if (doc) { bool found = false; Q_FOREACH (QPointer view, d->views) { if (view && view->document() == doc) { found = true; break; } } if (!found) { removeDocument(doc); } } } QList > KisPart::views() const { return d->views; } int KisPart::viewCount(KisDocument *doc) const { if (!doc) { return d->views.count(); } else { int count = 0; Q_FOREACH (QPointer view, d->views) { if (view && view->isVisible() && view->document() == doc) { count++; } } return count; } } bool KisPart::closingSession() const { return d->closingSession; } bool KisPart::closeSession(bool keepWindows) { d->closingSession = true; Q_FOREACH(auto document, d->documents) { if (!d->queryCloseDocument(document.data())) { d->closingSession = false; return false; } } if (d->currentSession) { KisConfig kisCfg(false); if (kisCfg.saveSessionOnQuit(false)) { d->currentSession->storeCurrentWindows(); d->currentSession->save(); KConfigGroup cfg = KSharedConfig::openConfig()->group("session"); cfg.writeEntry("previousSession", d->currentSession->name()); } d->currentSession = nullptr; } if (!keepWindows) { Q_FOREACH (auto window, d->mainWindows) { window->close(); } if (d->sessionManager) { d->sessionManager->close(); } } d->closingSession = false; return true; } void KisPart::slotDocumentSaved() { KisDocument *doc = qobject_cast(sender()); emit sigDocumentSaved(doc->url().toLocalFile()); } void KisPart::removeMainWindow(KisMainWindow *mainWindow) { dbgUI <<"mainWindow" << (void*)mainWindow <<"removed from doc" << this; if (mainWindow) { d->mainWindows.removeAll(mainWindow); } } const QList > &KisPart::mainWindows() const { return d->mainWindows; } int KisPart::mainwindowCount() const { return d->mainWindows.count(); } KisMainWindow *KisPart::currentMainwindow() const { QWidget *widget = qApp->activeWindow(); KisMainWindow *mainWindow = qobject_cast(widget); while (!mainWindow && widget) { widget = widget->parentWidget(); mainWindow = qobject_cast(widget); } if (!mainWindow && mainWindows().size() > 0) { mainWindow = mainWindows().first(); } return mainWindow; } KisMainWindow * KisPart::windowById(QUuid id) const { Q_FOREACH(QPointer mainWindow, d->mainWindows) { if (mainWindow->id() == id) { return mainWindow; } } return nullptr; } KisIdleWatcher* KisPart::idleWatcher() const { return &d->idleWatcher; } KisAnimationCachePopulator* KisPart::cachePopulator() const { return &d->animationCachePopulator; } void KisPart::openExistingFile(const QUrl &url) { // TODO: refactor out this method! KisMainWindow *mw = currentMainwindow(); KIS_SAFE_ASSERT_RECOVER_RETURN(mw); mw->openDocument(url, KisMainWindow::None); } void KisPart::updateShortcuts() { // Update any non-UI actionCollections. That includes: // - Shortcuts called inside of tools // - Perhaps other things? KoToolManager::instance()->updateToolShortcuts(); // Now update the UI actions. Q_FOREACH (KisMainWindow *mainWindow, d->mainWindows) { KActionCollection *ac = mainWindow->actionCollection(); ac->updateShortcuts(); // Loop through mainWindow->actionCollections() to modify tooltips // so that they list shortcuts at the end in parentheses Q_FOREACH ( QAction* action, ac->actions()) { // Remove any existing suffixes from the tooltips. // Note this regexp starts with a space, e.g. " (Ctrl-a)" QString strippedTooltip = action->toolTip().remove(QRegExp("\\s\\(.*\\)")); // Now update the tooltips with the new shortcut info. if(action->shortcut() == QKeySequence(0)) action->setToolTip(strippedTooltip); else action->setToolTip( strippedTooltip + " (" + action->shortcut().toString() + ")"); } } } void KisPart::openTemplate(const QUrl &url) { qApp->setOverrideCursor(Qt::BusyCursor); KisDocument *document = createDocument(); bool ok = document->loadNativeFormat(url.toLocalFile()); document->setModified(false); document->undoStack()->clear(); if (ok) { QString mimeType = KisMimeDatabase::mimeTypeForFile(url.toLocalFile()); // in case this is a open document template remove the -template from the end mimeType.remove( QRegExp( "-template$" ) ); document->setMimeTypeAfterLoading(mimeType); document->resetURL(); } else { if (document->errorMessage().isEmpty()) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not create document from template\n%1", document->localFilePath())); } else { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not create document from template\n%1\nReason: %2", document->localFilePath(), document->errorMessage())); } delete document; return; } addDocument(document); KisMainWindow *mw = currentMainwindow(); mw->addViewAndNotifyLoadingCompleted(document); KisOpenPane *pane = qobject_cast(sender()); if (pane) { pane->hide(); pane->deleteLater(); } qApp->restoreOverrideCursor(); } void KisPart::addRecentURLToAllMainWindows(QUrl url) { // Add to recent actions list in our mainWindows Q_FOREACH (KisMainWindow *mainWindow, d->mainWindows) { mainWindow->addRecentURL(url); } } void KisPart::startCustomDocument(KisDocument* doc) { addDocument(doc); KisMainWindow *mw = currentMainwindow(); KisOpenPane *pane = qobject_cast(sender()); if (pane) { pane->hide(); pane->deleteLater(); } mw->addViewAndNotifyLoadingCompleted(doc); } KisInputManager* KisPart::currentInputManager() { KisMainWindow *mw = currentMainwindow(); KisViewManager *manager = mw ? mw->viewManager() : 0; return manager ? manager->inputManager() : 0; } void KisPart::showSessionManager() { if (d->sessionManager.isNull()) { d->sessionManager.reset(new KisSessionManagerDialog()); } d->sessionManager->show(); d->sessionManager->activateWindow(); } void KisPart::startBlankSession() { KisMainWindow *window = createMainWindow(); window->initializeGeometry(); window->show(); } bool KisPart::restoreSession(const QString &sessionName) { if (sessionName.isNull()) return false; - KoResourceServer * rserver = KisResourceServerProvider::instance()->sessionServer(); - auto *session = rserver->resourceByName(sessionName); + KoResourceServer *rserver = KisResourceServerProvider::instance()->sessionServer(); + KisSessionResourceSP session = rserver->resourceByName(sessionName); if (!session || !session->valid()) return false; session->restore(); return true; } -void KisPart::setCurrentSession(KisSessionResource *session) +void KisPart::setCurrentSession(KisSessionResourceSP session) { d->currentSession = session; } diff --git a/libs/ui/KisPart.h b/libs/ui/KisPart.h index 79078319ee..7ea16f4909 100644 --- a/libs/ui/KisPart.h +++ b/libs/ui/KisPart.h @@ -1,276 +1,278 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis Copyright (C) 2000-2005 David Faure Copyright (C) 2007 Thorsten Zachmann Copyright (C) 2010 Boudewijn Rempt Copyright (C) 2015 Michael Abrahams This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KIS_PART_H #define KIS_PART_H #include #include #include #include +#include + #include "kritaui_export.h" #include #include #include namespace KIO { } class KisAction; class KisDocument; class KisView; class KisDocument; class KisIdleWatcher; class KisAnimationCachePopulator; -class KisSessionResource; + /** * KisPart is the Great Deku Tree of Krita. * * It is a singleton class which provides the main entry point to the application. * Krita supports multiple documents, multiple main windows, and multiple * components. KisPart manages these resources and provides them to the rest of * Krita. It manages lists of Actions and shortcuts as well. * * The terminology comes from KParts, which is a system allowing one KDE app * to be run from inside another, like pressing F4 inside dophin to run konsole. * * Needless to say, KisPart hasn't got much to do with KParts anymore. */ class KRITAUI_EXPORT KisPart : public QObject { Q_OBJECT public: static KisPart *instance(); /** * Constructor. * * @param parent may be another KisDocument, or anything else. * Usually passed by KPluginFactory::create. */ explicit KisPart(); /** * Destructor. * * The destructor does not delete any attached KisView objects and it does not * delete the attached widget as returned by widget(). */ ~KisPart() override; // ----------------- Document management ----------------- /** * create an empty document. The document is not automatically registered with the part. */ KisDocument *createDocument() const; /** * Add the specified document to the list of documents this KisPart manages. */ void addDocument(KisDocument *document); /** * @return a list of all documents this part manages */ QList > documents() const; /** * @return number of documents this part manages. */ int documentCount() const; void removeDocument(KisDocument *document); // ----------------- MainWindow management ----------------- /** * Create a new main window. */ KisMainWindow *createMainWindow(QUuid id = QUuid()); /** * Removes a main window from the list of managed windows. * * This is called by the MainWindow after it finishes its shutdown routine. */ void removeMainWindow(KisMainWindow *mainWindow); /** * @return the list of main windows. */ const QList >& mainWindows() const; /** * @return the number of shells for the main window */ int mainwindowCount() const; void addRecentURLToAllMainWindows(QUrl url); /** * @return the currently active main window. */ KisMainWindow *currentMainwindow() const; KisMainWindow *windowById(QUuid id) const; /** * @return the application-wide KisIdleWatcher. */ KisIdleWatcher *idleWatcher() const; /** * @return the application-wide AnimationCachePopulator. */ KisAnimationCachePopulator *cachePopulator() const; public Q_SLOTS: /** * This slot loads an existing file. * @param url the file to load */ void openExistingFile(const QUrl &url); /** * This slot loads a template and deletes the sender. * @param url the template to load */ void openTemplate(const QUrl &url); /** * @brief startCustomDocument adds the given document to the document list and deletes the sender() * @param doc */ void startCustomDocument(KisDocument *doc); private Q_SLOTS: void updateIdleWatcherConnections(); void updateShortcuts(); Q_SIGNALS: /** * emitted when a new document is opened. (for the idle watcher) */ void documentOpened(const QString &ref); /** * emitted when an old document is closed. (for the idle watcher) */ void documentClosed(const QString &ref); // These signals are for libkis or sketch void sigViewAdded(KisView *view); void sigViewRemoved(KisView *view); void sigDocumentAdded(KisDocument *document); void sigDocumentSaved(const QString &url); void sigDocumentRemoved(const QString &filename); void sigWindowAdded(KisMainWindow *window); public: KisInputManager *currentInputManager(); //------------------ View management ------------------ /** * Create a new view for the document. The view is added to the list of * views, and if the document wasn't known yet, it's registered as well. */ KisView *createView(KisDocument *document, KoCanvasResourceProvider *resourceManager, KActionCollection *actionCollection, QWidget *parent); /** * Adds a view to the document. If the part doesn't know yet about * the document, it is registered. * * This calls KisView::updateReadWrite to tell the new view * whether the document is readonly or not. */ void addView(KisView *view); /** * Removes a view of the document. */ void removeView(KisView *view); /** * @return a list of views this document is displayed in */ QList > views() const; /** * @return number of views this document is displayed in */ int viewCount(KisDocument *doc) const; //------------------ Session management ------------------ void showSessionManager(); void startBlankSession(); /** * Restores a saved session by name */ bool restoreSession(const QString &sessionName); - void setCurrentSession(KisSessionResource *session); + void setCurrentSession(KisSessionResourceSP session); /** * Attempts to save the session and close all windows. * This may involve asking the user to save open files. * @return false, if closing was cancelled by the user */ bool closeSession(bool keepWindows = false); /** * Are we in the process of closing the application through closeSession(). */ bool closingSession() const; private Q_SLOTS: void slotDocumentSaved(); private: Q_DISABLE_COPY(KisPart) class Private; Private *const d; }; #endif diff --git a/libs/ui/KisResourceBundle.cpp b/libs/ui/KisResourceBundle.cpp index 6b521ced55..d80ce0191e 100644 --- a/libs/ui/KisResourceBundle.cpp +++ b/libs/ui/KisResourceBundle.cpp @@ -1,1098 +1,1098 @@ /* * Copyright (c) 2014 Victor Lafon metabolic.ewilan@hotmail.fr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KisResourceBundle.h" #include "KisResourceBundleManifest.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include - +#include #include KisResourceBundle::KisResourceBundle(QString const& fileName) : KoResource(fileName), m_bundleVersion("1") { setName(QFileInfo(fileName).baseName()); m_metadata["generator"] = "Krita (" + KritaVersionWrapper::versionString(true) + ")"; } KisResourceBundle::~KisResourceBundle() { } QString KisResourceBundle::defaultFileExtension() const { return QString(".bundle"); } bool KisResourceBundle::load() { if (filename().isEmpty()) return false; QScopedPointer resourceStore(KoStore::createStore(filename(), KoStore::Read, "application/x-krita-resourcebundle", KoStore::Zip)); if (!resourceStore || resourceStore->bad()) { warnKrita << "Could not open store on bundle" << filename(); m_installed = false; setValid(false); return false; } else { m_metadata.clear(); bool toRecreate = false; if (resourceStore->open("META-INF/manifest.xml")) { if (!m_manifest.load(resourceStore->device())) { warnKrita << "Could not open manifest for bundle" << filename(); return false; } resourceStore->close(); Q_FOREACH (KisResourceBundleManifest::ResourceReference ref, m_manifest.files()) { if (!resourceStore->open(ref.resourcePath)) { warnKrita << "Bundle is broken. File" << ref.resourcePath << "is missing"; toRecreate = true; } else { resourceStore->close(); } } if(toRecreate) { warnKrita << "Due to missing files and wrong entries in the manifest, " << filename() << " will be recreated."; } } else { warnKrita << "Could not load META-INF/manifest.xml"; return false; } bool versionFound = false; if (resourceStore->open("meta.xml")) { KoXmlDocument doc; if (!doc.setContent(resourceStore->device())) { warnKrita << "Could not parse meta.xml for" << filename(); return false; } // First find the manifest:manifest node. KoXmlNode n = doc.firstChild(); for (; !n.isNull(); n = n.nextSibling()) { if (!n.isElement()) { continue; } if (n.toElement().tagName() == "meta:meta") { break; } } if (n.isNull()) { warnKrita << "Could not find manifest node for bundle" << filename(); return false; } const KoXmlElement metaElement = n.toElement(); for (n = metaElement.firstChild(); !n.isNull(); n = n.nextSibling()) { if (n.isElement()) { KoXmlElement e = n.toElement(); if (e.tagName() == "meta:generator") { m_metadata.insert("generator", e.firstChild().toText().data()); } else if (e.tagName() == "dc:author") { m_metadata.insert("author", e.firstChild().toText().data()); } else if (e.tagName() == "dc:title") { m_metadata.insert("title", e.firstChild().toText().data()); } else if (e.tagName() == "dc:description") { m_metadata.insert("description", e.firstChild().toText().data()); } else if (e.tagName() == "meta:initial-creator") { m_metadata.insert("author", e.firstChild().toText().data()); } else if (e.tagName() == "dc:creator") { m_metadata.insert("author", e.firstChild().toText().data()); } else if (e.tagName() == "meta:creation-date") { m_metadata.insert("created", e.firstChild().toText().data()); } else if (e.tagName() == "meta:dc-date") { m_metadata.insert("updated", e.firstChild().toText().data()); } else if (e.tagName() == "meta:meta-userdefined") { if (e.attribute("meta:name") == "tag") { m_bundletags << e.attribute("meta:value"); } else { m_metadata.insert(e.attribute("meta:name"), e.attribute("meta:value")); } } else if(e.tagName() == "meta:bundle-version") { m_metadata.insert("bundle-version", e.firstChild().toText().data()); versionFound = true; } } } resourceStore->close(); } else { warnKrita << "Could not load meta.xml"; return false; } if (resourceStore->open("preview.png")) { // Workaround for some OS (Debian, Ubuntu), where loading directly from the QIODevice // fails with "libpng error: IDAT: CRC error" QByteArray data = resourceStore->device()->readAll(); QBuffer buffer(&data); m_thumbnail.load(&buffer, "PNG"); resourceStore->close(); } else { warnKrita << "Could not open preview.png"; } /* * If no version is found it's an old bundle with md5 hashes to fix, or if some manifest resource entry * doesn't not correspond to a file the bundle is "broken", in both cases we need to recreate the bundle. */ if (!versionFound) { m_metadata.insert("bundle-version", "1"); warnKrita << filename() << " has an old version and possibly wrong resources md5, so it will be recreated."; toRecreate = true; } if (toRecreate) { recreateBundle(resourceStore); } m_installed = true; setValid(true); setImage(m_thumbnail); } return true; } bool KisResourceBundle::loadFromDevice(QIODevice *) { return false; } -bool saveResourceToStore(KoResource *resource, KoStore *store, const QString &resType) +bool saveResourceToStore(KoResourceSP resource, KoStore *store, const QString &resType) { if (!resource) { warnKrita << "No Resource"; return false; } if (!resource->valid()) { warnKrita << "Resource is not valid"; return false; } if (!store || store->bad()) { warnKrita << "No Store or Store is Bad"; return false; } QByteArray ba; QBuffer buf; QFileInfo fi(resource->filename()); if (fi.exists() && fi.isReadable()) { QFile f(resource->filename()); if (!f.open(QFile::ReadOnly)) { warnKrita << "Could not open resource" << resource->filename(); return false; } ba = f.readAll(); if (ba.size() == 0) { warnKrita << "Resource is empty" << resource->filename(); return false; } f.close(); buf.setBuffer(&ba); } else { warnKrita << "Could not find the resource " << resource->filename() << " or it isn't readable"; return false; } if (!buf.open(QBuffer::ReadOnly)) { warnKrita << "Could not open buffer"; return false; } Q_ASSERT(!store->hasFile(resType + "/" + resource->shortFilename())); if (!store->open(resType + "/" + resource->shortFilename())) { warnKrita << "Could not open file in store for resource"; return false; } bool res = (store->write(buf.data()) == buf.size()); store->close(); return res; } bool KisResourceBundle::save() { if (filename().isEmpty()) return false; addMeta("updated", QDate::currentDate().toString("dd/MM/yyyy")); QDir bundleDir = KoResourcePaths::saveLocation("data", "bundles"); bundleDir.cdUp(); QScopedPointer store(KoStore::createStore(filename(), KoStore::Write, "application/x-krita-resourcebundle", KoStore::Zip)); if (!store || store->bad()) return false; Q_FOREACH (const QString &resType, m_manifest.types()) { if (resType == "gradients") { KoResourceServer* gradientServer = KoResourceServerProvider::instance()->gradientServer(); Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { - KoResource *res = gradientServer->resourceByMD5(ref.md5sum); + KoResourceSP res = gradientServer->resourceByMD5(ref.md5sum); if (!res) res = gradientServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName()); if (!saveResourceToStore(res, store.data(), "gradients")) { if (res) { warnKrita << "Could not save resource" << resType << res->name(); } else { warnKrita << "could not find resource for" << QFileInfo(ref.resourcePath).fileName(); } } } } else if (resType == "patterns") { KoResourceServer* patternServer = KoResourceServerProvider::instance()->patternServer(); Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { - KoResource *res = patternServer->resourceByMD5(ref.md5sum); + KoResourceSP res = patternServer->resourceByMD5(ref.md5sum); if (!res) res = patternServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName()); if (!saveResourceToStore(res, store.data(), "patterns")) { if (res) { warnKrita << "Could not save resource" << resType << res->name(); } else { warnKrita << "could not find resource for" << QFileInfo(ref.resourcePath).fileName(); } } } } else if (resType == "brushes") { KisBrushResourceServer* brushServer = KisBrushServer::instance()->brushServer(); Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { KisBrushSP brush = brushServer->resourceByMD5(ref.md5sum); if (!brush) brush = brushServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName()); - KoResource *res = brush.data(); + KoResourceSP res = brush; if (!saveResourceToStore(res, store.data(), "brushes")) { if (res) { warnKrita << "Could not save resource" << resType << res->name(); } else { warnKrita << "could not find resource for" << QFileInfo(ref.resourcePath).fileName(); } } } } else if (resType == "palettes") { KoResourceServer* paletteServer = KoResourceServerProvider::instance()->paletteServer(); Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { - KoResource *res = paletteServer->resourceByMD5(ref.md5sum); + KoResourceSP res = paletteServer->resourceByMD5(ref.md5sum); if (!res) res = paletteServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName()); if (!saveResourceToStore(res, store.data(), "palettes")) { if (res) { warnKrita << "Could not save resource" << resType << res->name(); } else { warnKrita << "could not find resource for" << QFileInfo(ref.resourcePath).fileName(); } } } } else if (resType == "workspaces") { KoResourceServer< KisWorkspaceResource >* workspaceServer = KisResourceServerProvider::instance()->workspaceServer(); Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { - KoResource *res = workspaceServer->resourceByMD5(ref.md5sum); + KoResourceSP res = workspaceServer->resourceByMD5(ref.md5sum); if (!res) res = workspaceServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName()); if (!saveResourceToStore(res, store.data(), "workspaces")) { if (res) { warnKrita << "Could not save resource" << resType << res->name(); } else { warnKrita << "could not find resource for" << QFileInfo(ref.resourcePath).fileName(); } } } } else if (resType == "paintoppresets") { KisPaintOpPresetResourceServer* paintoppresetServer = KisResourceServerProvider::instance()->paintOpPresetServer(); Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { KisPaintOpPresetSP res = paintoppresetServer->resourceByMD5(ref.md5sum); if (!res) res = paintoppresetServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName()); - if (!saveResourceToStore(res.data(), store.data(), "paintoppresets")) { + if (!saveResourceToStore(res, store.data(), "paintoppresets")) { if (res) { warnKrita << "Could not save resource" << resType << res->name(); } else { warnKrita << "could not find resource for" << QFileInfo(ref.resourcePath).fileName(); } } } } else if (resType == "gamutmasks") { KoResourceServer* gamutMaskServer = KoResourceServerProvider::instance()->gamutMaskServer(); Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { - KoResource *res = gamutMaskServer->resourceByMD5(ref.md5sum); + KoResourceSP res = gamutMaskServer->resourceByMD5(ref.md5sum); if (!res) res = gamutMaskServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName()); if (!saveResourceToStore(res, store.data(), "gamutmasks")) { if (res) { warnKrita << "Could not save resource" << resType << res->name(); } else { warnKrita << "could not find resource for" << QFileInfo(ref.resourcePath).fileName(); } } } } } if (!m_thumbnail.isNull()) { QByteArray byteArray; QBuffer buffer(&byteArray); m_thumbnail.save(&buffer, "PNG"); if (!store->open("preview.png")) warnKrita << "Could not open preview.png"; if (store->write(byteArray) != buffer.size()) warnKrita << "Could not write preview.png"; store->close(); } saveManifest(store); saveMetadata(store); store->finalize(); return true; } bool KisResourceBundle::saveToDevice(QIODevice */*dev*/) const { return false; } bool KisResourceBundle::install() { QStringList md5Mismatch; if (filename().isEmpty()) { warnKrita << "Cannot install bundle: no file name" << this; return false; } QScopedPointer resourceStore(KoStore::createStore(filename(), KoStore::Read, "application/x-krita-resourcebundle", KoStore::Zip)); if (!resourceStore || resourceStore->bad()) { warnKrita << "Cannot open the resource bundle: invalid zip file?"; return false; } Q_FOREACH (const QString &resType, m_manifest.types()) { dbgResources << "Installing resource type" << resType; if (resType == "gradients") { KoResourceServer* gradientServer = KoResourceServerProvider::instance()->gradientServer(); Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { if (resourceStore->isOpen()) resourceStore->close(); dbgResources << "\tInstalling" << ref.resourcePath; - KoAbstractGradient *res = gradientServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath)); + KoAbstractGradientSP res = gradientServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath)); if (!res) { warnKrita << "Could not create resource for" << ref.resourcePath; continue; } if (!resourceStore->open(ref.resourcePath)) { warnKrita << "Failed to open" << ref.resourcePath << "from bundle" << filename(); continue; } if (!res->loadFromDevice(resourceStore->device())) { warnKrita << "Failed to load" << ref.resourcePath << "from bundle" << filename(); continue; } dbgResources << "\t\tresource:" << res->name(); - KoAbstractGradient *res2 = gradientServer->resourceByName(res->name()); + KoAbstractGradientSP res2 = gradientServer->resourceByName(res->name()); if (!res2) {//if it doesn't exist... gradientServer->addResource(res, false);//add it! if (!m_gradientsMd5Installed.contains(res->md5())) { m_gradientsMd5Installed.append(res->md5()); } if (ref.md5sum!=res->md5()) { md5Mismatch.append(res->name()); } Q_FOREACH (const QString &tag, ref.tagList) { gradientServer->addTag(res, tag); } //gradientServer->addTag(res, name()); } else { //warnKrita << "Didn't install" << res->name()<<"It already exists on the server"; } } } else if (resType == "patterns") { KoResourceServer* patternServer = KoResourceServerProvider::instance()->patternServer(); Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { if (resourceStore->isOpen()) resourceStore->close(); dbgResources << "\tInstalling" << ref.resourcePath; - KoPattern *res = patternServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath)); + KoPatternSP res = patternServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath)); if (!res) { warnKrita << "Could not create resource for" << ref.resourcePath; continue; } if (!resourceStore->open(ref.resourcePath)) { warnKrita << "Failed to open" << ref.resourcePath << "from bundle" << filename(); continue; } if (!res->loadFromDevice(resourceStore->device())) { warnKrita << "Failed to load" << ref.resourcePath << "from bundle" << filename(); continue; } dbgResources << "\t\tresource:" << res->name(); - KoPattern *res2 = patternServer->resourceByName(res->name()); + KoPatternSP res2 = patternServer->resourceByName(res->name()); if (!res2) {//if it doesn't exist... patternServer->addResource(res, false);//add it! if (!m_patternsMd5Installed.contains(res->md5())) { m_patternsMd5Installed.append(res->md5()); } if (ref.md5sum!=res->md5()) { md5Mismatch.append(res->name()); } Q_FOREACH (const QString &tag, ref.tagList) { patternServer->addTag(res, tag); } //patternServer->addTag(res, name()); } } } else if (resType == "brushes") { KisBrushResourceServer *brushServer = KisBrushServer::instance()->brushServer(); Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { if (resourceStore->isOpen()) resourceStore->close(); dbgResources << "\tInstalling" << ref.resourcePath; KisBrushSP res = brushServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath)); if (!res) { warnKrita << "Could not create resource for" << ref.resourcePath; continue; } if (!resourceStore->open(ref.resourcePath)) { warnKrita << "Failed to open" << ref.resourcePath << "from bundle" << filename(); continue; } if (!res->loadFromDevice(resourceStore->device())) { warnKrita << "Failed to load" << ref.resourcePath << "from bundle" << filename(); continue; } dbgResources << "\t\tresource:" << res->name(); //find the resource on the server KisBrushSP res2 = brushServer->resourceByName(res->name()); if (res2) { res->setName(res->name()+"("+res->shortFilename()+")"); } // file name is more important than the regular name because the // it is the way how it is called up from the brushpreset settings. // Therefore just adjust the resource name and only refuse to load // when the filename is different. res2 = brushServer->resourceByFilename(res->shortFilename()); if (!res2) {//if it doesn't exist... brushServer->addResource(res, false);//add it! if (!m_brushesMd5Installed.contains(res->md5())) { m_brushesMd5Installed.append(res->md5()); } if (ref.md5sum!=res->md5()) { md5Mismatch.append(res->name()); } Q_FOREACH (const QString &tag, ref.tagList) { - brushServer->addTag(res.data(), tag); + brushServer->addTag(res, tag); } - //brushServer->addTag(res.data(), name()); + //brushServer->addTag(res, name()); } else { //warnKrita << "Didn't install" << res->name()<<"It already exists on the server"; } } } else if (resType == "palettes") { KoResourceServer* paletteServer = KoResourceServerProvider::instance()->paletteServer(); Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { if (resourceStore->isOpen()) resourceStore->close(); dbgResources << "\tInstalling" << ref.resourcePath; - KoColorSet *res = paletteServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath)); + KoColorSetSP res = paletteServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath)); if (!res) { warnKrita << "Could not create resource for" << ref.resourcePath; continue; } if (!resourceStore->open(ref.resourcePath)) { warnKrita << "Failed to open" << ref.resourcePath << "from bundle" << filename(); continue; } if (!res->loadFromDevice(resourceStore->device())) { warnKrita << "Failed to load" << ref.resourcePath << "from bundle" << filename(); continue; } dbgResources << "\t\tresource:" << res->name(); //find the resource on the server - KoColorSet *res2 = paletteServer->resourceByName(res->name()); + KoColorSetSP res2 = paletteServer->resourceByName(res->name()); if (!res2) {//if it doesn't exist... paletteServer->addResource(res, false);//add it! if (!m_palettesMd5Installed.contains(res->md5())) { m_palettesMd5Installed.append(res->md5()); } if (ref.md5sum!=res->md5()) { md5Mismatch.append(res->name()); } Q_FOREACH (const QString &tag, ref.tagList) { paletteServer->addTag(res, tag); } //paletteServer->addTag(res, name()); } else { //warnKrita << "Didn't install" << res->name()<<"It already exists on the server"; } } } else if (resType == "workspaces") { KoResourceServer< KisWorkspaceResource >* workspaceServer = KisResourceServerProvider::instance()->workspaceServer(); Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { if (resourceStore->isOpen()) resourceStore->close(); dbgResources << "\tInstalling" << ref.resourcePath; - KisWorkspaceResource *res = workspaceServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath)); + KisWorkspaceResourceSP res = workspaceServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath)); if (!res) { warnKrita << "Could not create resource for" << ref.resourcePath; continue; } if (!resourceStore->open(ref.resourcePath)) { warnKrita << "Failed to open" << ref.resourcePath << "from bundle" << filename(); continue; } if (!res->loadFromDevice(resourceStore->device())) { warnKrita << "Failed to load" << ref.resourcePath << "from bundle" << filename(); continue; } dbgResources << "\t\tresource:" << res->name(); //the following tries to find the resource by name. - KisWorkspaceResource *res2 = workspaceServer->resourceByName(res->name()); + KisWorkspaceResourceSP res2 = workspaceServer->resourceByName(res->name()); if (!res2) {//if it doesn't exist... workspaceServer->addResource(res, false);//add it! if (!m_workspacesMd5Installed.contains(res->md5())) { m_workspacesMd5Installed.append(res->md5()); } if (ref.md5sum!=res->md5()) { md5Mismatch.append(res->name()); } Q_FOREACH (const QString &tag, ref.tagList) { workspaceServer->addTag(res, tag); } //workspaceServer->addTag(res, name()); } else { //warnKrita << "Didn't install" << res->name()<<"It already exists on the server"; } } } else if (resType == "paintoppresets") { KisPaintOpPresetResourceServer* paintoppresetServer = KisResourceServerProvider::instance()->paintOpPresetServer(); Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { if (resourceStore->isOpen()) resourceStore->close(); dbgResources << "\tInstalling" << ref.resourcePath; KisPaintOpPresetSP res = paintoppresetServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath)); if (!res) { warnKrita << "Could not create resource for" << ref.resourcePath; continue; } if (!resourceStore->open(ref.resourcePath)) { warnKrita << "Failed to open" << ref.resourcePath << "from bundle" << filename(); continue; } // Workaround for some OS (Debian, Ubuntu), where loading directly from the QIODevice // fails with "libpng error: IDAT: CRC error" QByteArray data = resourceStore->device()->readAll(); QBuffer buffer(&data); if (!res->loadFromDevice(&buffer)) { warnKrita << "Failed to load" << ref.resourcePath << "from bundle" << filename(); continue; } dbgResources << "\t\tresource:" << res->name() << "File:" << res->filename(); //the following tries to find the resource by name. KisPaintOpPresetSP res2 = paintoppresetServer->resourceByName(res->name()); if (!res2) {//if it doesn't exist... paintoppresetServer->addResource(res, false);//add it! if (!m_presetsMd5Installed.contains(res->md5())){ m_presetsMd5Installed.append(res->md5()); } if (ref.md5sum!=res->md5()) { md5Mismatch.append(res->name()); } Q_FOREACH (const QString &tag, ref.tagList) { - paintoppresetServer->addTag(res.data(), tag); + paintoppresetServer->addTag(res, tag); } - //paintoppresetServer->addTag(res.data(), name()); + //paintoppresetServer->addTag(res, name()); } else { //warnKrita << "Didn't install" << res->name()<<"It already exists on the server"; } } } else if (resType == "gamutmasks") { KoResourceServer* gamutMaskServer = KoResourceServerProvider::instance()->gamutMaskServer(); Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { if (resourceStore->isOpen()) resourceStore->close(); dbgResources << "\tInstalling" << ref.resourcePath; - KoGamutMask *res = gamutMaskServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath)); + KoGamutMaskSP res = gamutMaskServer->createResource(QString("bundle://%1:%2").arg(filename()).arg(ref.resourcePath)); if (!res) { warnKrita << "Could not create resource for" << ref.resourcePath; continue; } if (!resourceStore->open(ref.resourcePath)) { warnKrita << "Failed to open" << ref.resourcePath << "from bundle" << filename(); continue; } if (!res->loadFromDevice(resourceStore->device())) { warnKrita << "Failed to load" << ref.resourcePath << "from bundle" << filename(); continue; } dbgResources << "\t\tresource:" << res->name(); //find the resource on the server - KoGamutMask *res2 = gamutMaskServer->resourceByName(res->name()); + KoGamutMaskSP res2 = gamutMaskServer->resourceByName(res->name()); if (!res2) {//if it doesn't exist... gamutMaskServer->addResource(res, false);//add it! if (!m_gamutMasksMd5Installed.contains(res->md5())) { m_gamutMasksMd5Installed.append(res->md5()); } if (ref.md5sum!=res->md5()) { md5Mismatch.append(res->name()); } Q_FOREACH (const QString &tag, ref.tagList) { gamutMaskServer->addTag(res, tag); } //gamutMaskServer->addTag(res, name()); } else { //warnKrita << "Didn't install" << res->name()<<"It already exists on the server"; } } } } m_installed = true; if(!md5Mismatch.isEmpty()){ QString message = i18n("The following resources had mismatching MD5 sums. They may have gotten corrupted, for example, during download."); QMessageBox bundleFeedback; bundleFeedback.setIcon(QMessageBox::Warning); Q_FOREACH (QString name, md5Mismatch) { message.append("\n"); message.append(name); } bundleFeedback.setText(message); bundleFeedback.exec(); } return true; } bool KisResourceBundle::uninstall() { m_installed = false; QStringList tags = getTagsList(); tags << m_manifest.tags(); //tags << name(); KoResourceServer* gradientServer = KoResourceServerProvider::instance()->gradientServer(); //Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files("gradients")) { Q_FOREACH (const QByteArray md5, m_gradientsMd5Installed) { - KoAbstractGradient *res = gradientServer->resourceByMD5(md5); + KoAbstractGradientSP res = gradientServer->resourceByMD5(md5); if (res) { gradientServer->removeResourceFromServer(res); } } KoResourceServer* patternServer = KoResourceServerProvider::instance()->patternServer(); //Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files("patterns")) { Q_FOREACH (const QByteArray md5, m_patternsMd5Installed) { - KoPattern *res = patternServer->resourceByMD5(md5); + KoPatternSP res = patternServer->resourceByMD5(md5); if (res) { patternServer->removeResourceFromServer(res); } } KisBrushResourceServer *brushServer = KisBrushServer::instance()->brushServer(); //Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files("brushes")) { Q_FOREACH (const QByteArray md5, m_brushesMd5Installed) { KisBrushSP res = brushServer->resourceByMD5(md5); if (res) { brushServer->removeResourceFromServer(res); } } KoResourceServer* paletteServer = KoResourceServerProvider::instance()->paletteServer(); //Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files("palettes")) { Q_FOREACH (const QByteArray md5, m_palettesMd5Installed) { - KoColorSet *res = paletteServer->resourceByMD5(md5); + KoColorSetSP res = paletteServer->resourceByMD5(md5); if (res) { paletteServer->removeResourceFromServer(res); } } KoResourceServer< KisWorkspaceResource >* workspaceServer = KisResourceServerProvider::instance()->workspaceServer(); //Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files("workspaces")) { Q_FOREACH (const QByteArray md5, m_workspacesMd5Installed) { - KisWorkspaceResource *res = workspaceServer->resourceByMD5(md5); + KisWorkspaceResourceSP res = workspaceServer->resourceByMD5(md5); if (res) { workspaceServer->removeResourceFromServer(res); } } KisPaintOpPresetResourceServer* paintoppresetServer = KisResourceServerProvider::instance()->paintOpPresetServer(); //Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files("paintoppresets")) { Q_FOREACH (const QByteArray md5, m_presetsMd5Installed) { KisPaintOpPresetSP res = paintoppresetServer->resourceByMD5(md5); if (res) { paintoppresetServer->removeResourceFromServer(res); } } KoResourceServer* gamutMaskServer = KoResourceServerProvider::instance()->gamutMaskServer(); //Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files("gamutmasks")) { Q_FOREACH (const QByteArray md5, m_gamutMasksMd5Installed) { - KoGamutMask *res = gamutMaskServer->resourceByMD5(md5); + KoGamutMaskSP res = gamutMaskServer->resourceByMD5(md5); if (res) { gamutMaskServer->removeResourceFromServer(res); } } Q_FOREACH(const QString &tag, tags) { paintoppresetServer->tagCategoryRemoved(tag); workspaceServer->tagCategoryRemoved(tag); paletteServer->tagCategoryRemoved(tag); brushServer->tagCategoryRemoved(tag); patternServer->tagCategoryRemoved(tag); gradientServer->tagCategoryRemoved(tag); gamutMaskServer->tagCategoryRemoved(tag); } return true; } void KisResourceBundle::addMeta(const QString &type, const QString &value) { m_metadata.insert(type, value); } const QString KisResourceBundle::getMeta(const QString &type, const QString &defaultValue) const { if (m_metadata.contains(type)) { return m_metadata[type]; } else { return defaultValue; } } void KisResourceBundle::addResource(QString fileType, QString filePath, QStringList fileTagList, const QByteArray md5sum) { m_manifest.addResource(fileType, filePath, fileTagList, md5sum); } QList KisResourceBundle::getTagsList() { return QList::fromSet(m_bundletags); } bool KisResourceBundle::isInstalled() { return m_installed; } QStringList KisResourceBundle::resourceTypes() const { return m_manifest.types(); } -QList KisResourceBundle::resources(const QString &resType) const +QList KisResourceBundle::resources(const QString &resType) const { QList references = m_manifest.files(resType); - QList ret; + QList ret; Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, references) { if (resType == "gradients") { KoResourceServer* gradientServer = KoResourceServerProvider::instance()->gradientServer(); - KoResource *res = gradientServer->resourceByMD5(ref.md5sum); + KoResourceSP res = gradientServer->resourceByMD5(ref.md5sum); if (res) ret << res; } else if (resType == "patterns") { KoResourceServer* patternServer = KoResourceServerProvider::instance()->patternServer(); - KoResource *res = patternServer->resourceByMD5(ref.md5sum); + KoResourceSP res = patternServer->resourceByMD5(ref.md5sum); if (res) ret << res; } else if (resType == "brushes") { KisBrushResourceServer *brushServer = KisBrushServer::instance()->brushServer(); - KoResource *res = brushServer->resourceByMD5(ref.md5sum).data(); + KoResourceSP res = brushServer->resourceByMD5(ref.md5sum); if (res) ret << res; } else if (resType == "palettes") { KoResourceServer* paletteServer = KoResourceServerProvider::instance()->paletteServer(); - KoResource *res = paletteServer->resourceByMD5(ref.md5sum); + KoResourceSP res = paletteServer->resourceByMD5(ref.md5sum); if (res) ret << res; } else if (resType == "workspaces") { KoResourceServer< KisWorkspaceResource >* workspaceServer = KisResourceServerProvider::instance()->workspaceServer(); - KoResource *res = workspaceServer->resourceByMD5(ref.md5sum); + KoResourceSP res = workspaceServer->resourceByMD5(ref.md5sum); if (res) ret << res; } else if (resType == "paintoppresets") { KisPaintOpPresetResourceServer* paintoppresetServer = KisResourceServerProvider::instance()->paintOpPresetServer(); KisPaintOpPresetSP res = paintoppresetServer->resourceByMD5(ref.md5sum); - if (res) ret << res.data(); + if (res) ret << res; } else if (resType == "gamutmasks") { KoResourceServer* gamutMaskServer = KoResourceServerProvider::instance()->gamutMaskServer(); - KoResource *res = gamutMaskServer->resourceByMD5(ref.md5sum); + KoResourceSP res = gamutMaskServer->resourceByMD5(ref.md5sum); if (res) ret << res; } } return ret; } void KisResourceBundle::setThumbnail(QString filename) { if (QFileInfo(filename).exists()) { m_thumbnail = QImage(filename); m_thumbnail = m_thumbnail.scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation); } else { m_thumbnail = QImage(256, 256, QImage::Format_ARGB32); QPainter gc(&m_thumbnail); gc.fillRect(0, 0, 256, 256, Qt::red); gc.end(); } setImage(m_thumbnail); } void KisResourceBundle::writeMeta(const char *metaTag, const QString &metaKey, KoXmlWriter *writer) { if (m_metadata.contains(metaKey)) { writer->startElement(metaTag); writer->addTextNode(m_metadata[metaKey].toUtf8()); writer->endElement(); } } void KisResourceBundle::writeUserDefinedMeta(const QString &metaKey, KoXmlWriter *writer) { if (m_metadata.contains(metaKey)) { writer->startElement("meta:meta-userdefined"); writer->addAttribute("meta:name", metaKey); writer->addAttribute("meta:value", m_metadata[metaKey]); writer->endElement(); } } void KisResourceBundle::setInstalled(bool install) { m_installed = install; } void KisResourceBundle::saveMetadata(QScopedPointer &store) { QBuffer buf; store->open("meta.xml"); buf.open(QBuffer::WriteOnly); KoXmlWriter metaWriter(&buf); metaWriter.startDocument("office:document-meta"); metaWriter.startElement("meta:meta"); writeMeta("meta:generator", "generator", &metaWriter); metaWriter.startElement("meta:bundle-version"); metaWriter.addTextNode(m_bundleVersion.toUtf8()); metaWriter.endElement(); writeMeta("dc:author", "author", &metaWriter); writeMeta("dc:title", "filename", &metaWriter); writeMeta("dc:description", "description", &metaWriter); writeMeta("meta:initial-creator", "author", &metaWriter); writeMeta("dc:creator", "author", &metaWriter); writeMeta("meta:creation-date", "created", &metaWriter); writeMeta("meta:dc-date", "updated", &metaWriter); writeUserDefinedMeta("email", &metaWriter); writeUserDefinedMeta("license", &metaWriter); writeUserDefinedMeta("website", &metaWriter); Q_FOREACH (const QString &tag, m_bundletags) { metaWriter.startElement("meta:meta-userdefined"); metaWriter.addAttribute("meta:name", "tag"); metaWriter.addAttribute("meta:value", tag); metaWriter.endElement(); } metaWriter.endElement(); // meta:meta metaWriter.endDocument(); buf.close(); store->write(buf.data()); store->close(); } void KisResourceBundle::saveManifest(QScopedPointer &store) { store->open("META-INF/manifest.xml"); QBuffer buf; buf.open(QBuffer::WriteOnly); m_manifest.save(&buf); buf.close(); store->write(buf.data()); store->close(); } void KisResourceBundle::recreateBundle(QScopedPointer &oldStore) { // Save a copy of the unmodified bundle, so that if anything goes bad the user doesn't lose it QFile file(filename()); file.copy(filename() + ".old"); QString newStoreName = filename() + ".tmp"; { QScopedPointer store(KoStore::createStore(newStoreName, KoStore::Write, "application/x-krita-resourcebundle", KoStore::Zip)); KoHashGenerator *generator = KoHashGeneratorProvider::instance()->getGenerator("MD5"); KisResourceBundleManifest newManifest; addMeta("updated", QDate::currentDate().toString("dd/MM/yyyy")); Q_FOREACH (KisResourceBundleManifest::ResourceReference ref, m_manifest.files()) { // Wrong manifest entry found, skip it if(!oldStore->open(ref.resourcePath)) continue; store->open(ref.resourcePath); QByteArray data = oldStore->device()->readAll(); oldStore->close(); store->write(data); store->close(); QByteArray result = generator->generateHash(data); newManifest.addResource(ref.fileTypeName, ref.resourcePath, ref.tagList, result); } m_manifest = newManifest; if (!m_thumbnail.isNull()) { QByteArray byteArray; QBuffer buffer(&byteArray); m_thumbnail.save(&buffer, "PNG"); if (!store->open("preview.png")) warnKrita << "Could not open preview.png"; if (store->write(byteArray) != buffer.size()) warnKrita << "Could not write preview.png"; store->close(); } saveManifest(store); saveMetadata(store); store->finalize(); } // Remove the current bundle and then move the tmp one to be the correct one file.setFileName(filename()); if (!file.remove()) { qWarning() << "Could not remove" << filename() << file.errorString(); } QFile f(newStoreName); Q_ASSERT(f.exists()); if (!f.copy(filename())) { qWarning() << "Could not copy the tmp file to the store" << filename() << newStoreName << QFile(newStoreName).exists() << f.errorString(); } } int KisResourceBundle::resourceCount() const { return m_manifest.files().count(); } diff --git a/libs/ui/KisResourceBundle.h b/libs/ui/KisResourceBundle.h index ff9d360ca1..43db4e25e9 100644 --- a/libs/ui/KisResourceBundle.h +++ b/libs/ui/KisResourceBundle.h @@ -1,160 +1,162 @@ /* * Copyright (c) 2014 Victor Lafon metabolic.ewilan@hotmail.fr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KORESOURCEBUNDLE_H #define KORESOURCEBUNDLE_H #include #include #include #include #include "KisResourceBundleManifest.h" #include "kritaui_export.h" class KoStore; /** * @brief The ResourceBundle class * @details Describe the resource bundles as KoResources */ class KRITAUI_EXPORT KisResourceBundle : public KoResource { public: /** * @brief ResourceBundle : Ctor * @param bundlePath the path of the bundle */ KisResourceBundle(QString const& fileName); /** * @brief ~ResourceBundle : Dtor */ ~KisResourceBundle() override; /** * @brief defaultFileExtension * @return the default file extension which should be when saving the resource */ QString defaultFileExtension() const override; /** * @brief load : Load this resource. * @return true if succeed, false otherwise. */ bool load() override; bool loadFromDevice(QIODevice *dev) override; /** * @brief save : Save this resource. * @return true if succeed, false otherwise. */ bool save() override; bool saveToDevice(QIODevice* dev) const override; /** * @brief install : Install the contents of the resource bundle. */ bool install(); /** * @brief uninstall : Uninstall the resource bundle. */ bool uninstall(); /** * @brief addMeta : Add a Metadata to the resource * @param type type of the metadata * @param value value of the metadata */ void addMeta(const QString &type, const QString &value); const QString getMeta(const QString &type, const QString &defaultValue = QString()) const; /** * @brief addFile : Add a file to the bundle * @param fileType type of the resource file * @param filePath path of the resource file */ void addResource(QString fileType, QString filePath, QStringList fileTagList, const QByteArray md5sum); QList getTagsList(); /** * @brief isInstalled * @return true if the bundle is installed, false otherwise. */ bool isInstalled(); /** * @brief setInstalled * This allows you to set installed or uninstalled upon loading. This is used with blacklists. */ void setInstalled(bool install); void setThumbnail(QString); /** * @brief saveMetadata: saves bundle metadata * @param store bundle where to save the metadata */ void saveMetadata(QScopedPointer &store); /** * @brief saveManifest: saves bundle manifest * @param store bundle where to save the manifest */ void saveManifest(QScopedPointer &store); /** * @brief recreateBundle * It recreates the bundle by copying the old bundle information to a new store * and recalculating the md5 of each resource. * @param oldStore the old store to be recreated. */ void recreateBundle(QScopedPointer &oldStore); QStringList resourceTypes() const; - QList resources(const QString &resType = QString()) const; + QList resources(const QString &resType = QString()) const; int resourceCount() const; private: void writeMeta(const char *metaTag, const QString &metaKey, KoXmlWriter *writer); void writeUserDefinedMeta(const QString &metaKey, KoXmlWriter *writer); private: QImage m_thumbnail; KisResourceBundleManifest m_manifest; QMap m_metadata; QSet m_bundletags; bool m_installed; QList m_gradientsMd5Installed; QList m_patternsMd5Installed; QList m_brushesMd5Installed; QList m_palettesMd5Installed; QList m_workspacesMd5Installed; QList m_presetsMd5Installed; QList m_gamutMasksMd5Installed; QString m_bundleVersion; }; +typedef QSharedPointer KisResourceBundleSP; + #endif // KORESOURCEBUNDLE_H diff --git a/libs/ui/KisResourceBundleServerProvider.cpp b/libs/ui/KisResourceBundleServerProvider.cpp index 8a8f3f9c78..671a0f79da 100644 --- a/libs/ui/KisResourceBundleServerProvider.cpp +++ b/libs/ui/KisResourceBundleServerProvider.cpp @@ -1,68 +1,68 @@ /* * kis_resourceserver.cc - part of KImageShop * * Copyright (c) 1999 Matthias Elter * Copyright (c) 2003 Patrick Julien * Copyright (c) 2005 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 "KisResourceBundleServerProvider.h" #include "KisResourceServerProvider.h" #include #include #include #include #include #include #include #include #include Q_GLOBAL_STATIC(KisResourceBundleServerProvider, s_instance) KisResourceBundleServerProvider::KisResourceBundleServerProvider() { m_resourceBundleServer = new KoResourceServerSimpleConstruction("kis_resourcebundles", "*.bundle"); QStringList files = KoResourceServerProvider::blacklistFileNames(m_resourceBundleServer->fileNames(), m_resourceBundleServer->blackListedFiles()); // qDebug() << "Bundle files to load" << files; m_resourceBundleServer->loadResources(files); - Q_FOREACH (KisResourceBundle *bundle, m_resourceBundleServer->resources()) { + Q_FOREACH (KisResourceBundleSP bundle, m_resourceBundleServer->resources()) { if (!bundle->install()) { warnKrita << "Could not install resources for bundle" << bundle->name(); } } } KisResourceBundleServerProvider::~KisResourceBundleServerProvider() { delete m_resourceBundleServer; } KisResourceBundleServerProvider* KisResourceBundleServerProvider::instance() { return s_instance; } KoResourceServer *KisResourceBundleServerProvider::resourceBundleServer() { return m_resourceBundleServer; } diff --git a/libs/ui/KisResourceServerProvider.cpp b/libs/ui/KisResourceServerProvider.cpp index ecc495c68f..1c7687942c 100644 --- a/libs/ui/KisResourceServerProvider.cpp +++ b/libs/ui/KisResourceServerProvider.cpp @@ -1,120 +1,120 @@ /* * kis_resourceserver.cc - part of KImageShop * * Copyright (c) 1999 Matthias Elter * Copyright (c) 2003 Patrick Julien * Copyright (c) 2005 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 "KisResourceServerProvider.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include Q_GLOBAL_STATIC(KisResourceServerProvider, s_instance) -typedef KoResourceServerSimpleConstruction > KisPaintOpPresetResourceServer; -typedef KoResourceServerAdapter > KisPaintOpPresetResourceServerAdapter; +typedef KoResourceServerSimpleConstruction KisPaintOpPresetResourceServer; +typedef KoResourceServerAdapter KisPaintOpPresetResourceServerAdapter; KisResourceServerProvider::KisResourceServerProvider() { KisBrushServer *brushServer = KisBrushServer::instance(); m_paintOpPresetServer = new KisPaintOpPresetResourceServer("paintoppresets", "*.kpp"); m_paintOpPresetServer->loadResources(KoResourceServerProvider::blacklistFileNames(m_paintOpPresetServer->fileNames(), m_paintOpPresetServer->blackListedFiles())); m_workspaceServer = new KoResourceServerSimpleConstruction("workspaces", "*.kws"); m_workspaceServer->loadResources(KoResourceServerProvider::blacklistFileNames(m_workspaceServer->fileNames(), m_workspaceServer->blackListedFiles())); m_windowLayoutServer = new KoResourceServerSimpleConstruction("windowlayouts", "*.kwl"); m_windowLayoutServer->loadResources(KoResourceServerProvider::blacklistFileNames(m_windowLayoutServer->fileNames(), m_windowLayoutServer->blackListedFiles())); m_sessionServer = new KoResourceServerSimpleConstruction("sessions", "*.ksn"); m_sessionServer->loadResources(KoResourceServerProvider::blacklistFileNames(m_sessionServer->fileNames(), m_sessionServer->blackListedFiles())); m_layerStyleCollectionServer = new KoResourceServerSimpleConstruction("psd_layer_style_collections", "*.asl"); m_layerStyleCollectionServer->loadResources(KoResourceServerProvider::blacklistFileNames(m_layerStyleCollectionServer->fileNames(), m_layerStyleCollectionServer->blackListedFiles())); connect(this, SIGNAL(notifyBrushBlacklistCleanup()), brushServer, SLOT(slotRemoveBlacklistedResources())); } KisResourceServerProvider::~KisResourceServerProvider() { delete m_paintOpPresetServer; delete m_workspaceServer; delete m_sessionServer; delete m_windowLayoutServer; delete m_layerStyleCollectionServer; } KisResourceServerProvider* KisResourceServerProvider::instance() { return s_instance; } KisPaintOpPresetResourceServer* KisResourceServerProvider::paintOpPresetServer() { return m_paintOpPresetServer; } KoResourceServer< KisWorkspaceResource >* KisResourceServerProvider::workspaceServer() { return m_workspaceServer; } KoResourceServer< KisWindowLayoutResource >* KisResourceServerProvider::windowLayoutServer() { return m_windowLayoutServer; } KoResourceServer< KisSessionResource >* KisResourceServerProvider::sessionServer() { return m_sessionServer; } KoResourceServer *KisResourceServerProvider::layerStyleCollectionServer() { return m_layerStyleCollectionServer; } void KisResourceServerProvider::brushBlacklistCleanup() { emit notifyBrushBlacklistCleanup(); } diff --git a/libs/ui/KisResourceServerProvider.h b/libs/ui/KisResourceServerProvider.h index 8bf6eed962..45493d459b 100644 --- a/libs/ui/KisResourceServerProvider.h +++ b/libs/ui/KisResourceServerProvider.h @@ -1,75 +1,75 @@ /* * kis_resource_server_provider.h - part of KImageShop * * Copyright (c) 1999 Matthias Elter * Copyright (c) 2003 Patrick Julien * Copyright (c) 2005 Sven Langkamp * Copyright (c) 2003-2008 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. */ #ifndef KIS_RESOURCESERVERPROVIDER_H_ #define KIS_RESOURCESERVERPROVIDER_H_ #include #include #include #include #include "kritaui_export.h" #include "KisWindowLayoutResource.h" class KisWorkspaceResource; class KisSessionResource; class KisPSDLayerStyleCollectionResource; -typedef KoResourceServerSimpleConstruction > KisPaintOpPresetResourceServer; -typedef KoResourceServerAdapter > KisPaintOpPresetResourceServerAdapter; +typedef KoResourceServerSimpleConstruction KisPaintOpPresetResourceServer; +typedef KoResourceServerAdapter KisPaintOpPresetResourceServerAdapter; class KRITAUI_EXPORT KisResourceServerProvider : public QObject { Q_OBJECT public: KisResourceServerProvider(); ~KisResourceServerProvider() override; static KisResourceServerProvider* instance(); KisPaintOpPresetResourceServer* paintOpPresetServer(); KoResourceServer* workspaceServer(); KoResourceServer* windowLayoutServer(); KoResourceServer* sessionServer(); KoResourceServer* layerStyleCollectionServer(); void brushBlacklistCleanup(); Q_SIGNALS: void notifyBrushBlacklistCleanup(); private: KisResourceServerProvider(const KisResourceServerProvider&); KisResourceServerProvider operator=(const KisResourceServerProvider&); KisPaintOpPresetResourceServer *m_paintOpPresetServer; KoResourceServer *m_workspaceServer; KoResourceServer *m_windowLayoutServer; KoResourceServer *m_sessionServer; KoResourceServer *m_layerStyleCollectionServer; }; #endif // KIS_RESOURCESERVERPROVIDER_H_ diff --git a/libs/ui/KisSessionResource.cpp b/libs/ui/KisSessionResource.cpp index 0ac281b58c..63d0c28443 100644 --- a/libs/ui/KisSessionResource.cpp +++ b/libs/ui/KisSessionResource.cpp @@ -1,188 +1,189 @@ /* * Copyright (c) 2018 Jouni Pentikäinen * * 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 "KisSessionResource.h" #include #include #include #include #include #include struct KisSessionResource::Private { struct View { QUuid windowId; QUrl file; KisPropertiesConfiguration viewConfig; KisMainWindow *getWindow() const { Q_FOREACH(KisMainWindow *window, KisPart::instance()->mainWindows()) { if (window->id() == this->windowId) return window; } return nullptr; } }; QString profileName; QVector views; }; KisSessionResource::KisSessionResource(const QString &filename) : KisWindowLayoutResource(filename) , d(new Private) {} KisSessionResource::~KisSessionResource() {} void KisSessionResource::restore() { auto *kisPart = KisPart::instance(); applyLayout(); QMap documents; // Find documents which are already open so we don't need to reload them QList> oldViews = kisPart->views(); Q_FOREACH(const QPointer view, oldViews) { KisDocument *document = view->document(); const QUrl url = document->url(); documents.insert(url, document); } Q_FOREACH(auto &viewData, d->views) { QUrl url = viewData.file; KisMainWindow *window = viewData.getWindow(); if (!window) { qDebug() << "Warning: session file contains inconsistent data."; } else { KisDocument *document = documents.value(url); if (!document) { document = kisPart->createDocument(); bool ok = document->openUrl(url); if (!ok) { delete document; continue; } kisPart->addDocument(document); documents.insert(url, document); } //update profile QString profileName; profileName = d->profileName; window->viewManager()->changeAuthorProfile(profileName); window->viewManager()->slotUpdateAuthorProfileActions(); KisView *view = window->newView(document); view->restoreViewState(viewData.viewConfig); } } Q_FOREACH(QPointer view, oldViews) { view->closeView(); } - kisPart->setCurrentSession(this); + // XXX: SharedPtr breakage + kisPart->setCurrentSession(KisSessionResourceSP(this)); } QString KisSessionResource::defaultFileExtension() const { return ".ksn"; } void KisSessionResource::storeCurrentWindows() { KisPart *kisPart = KisPart::instance(); const auto &windows = kisPart->mainWindows(); setWindows(windows); d->views.clear(); Q_FOREACH(const KisView *view, kisPart->views()) { if (view->document()->url().isEmpty()) continue; auto viewData = Private::View(); viewData.windowId = view->mainWindow()->id(); viewData.file = view->document()->url(); view->saveViewState(viewData.viewConfig); d->views.append(viewData); } setValid(true); } void KisSessionResource::saveXml(QDomDocument &doc, QDomElement &root) const { KisWindowLayoutResource::saveXml(doc, root); Q_FOREACH(const auto view, d->views) { QDomElement elem = doc.createElement("view"); elem.setAttribute("window", view.windowId.toString()); elem.setAttribute("src", view.file.toString()); view.viewConfig.toXML(doc, elem); root.appendChild(elem); // Save profile KConfigGroup appAuthorGroup(KSharedConfig::openConfig(), "Author"); QString profileName = appAuthorGroup.readEntry("active-profile", ""); QDomElement session = doc.createElement("session"); session.setAttribute("profile", profileName); root.appendChild(session); } } void KisSessionResource::loadXml(const QDomElement &root) const { KisWindowLayoutResource::loadXml(root); d->views.clear(); for (auto viewElement = root.firstChildElement("view"); !viewElement.isNull(); viewElement = viewElement.nextSiblingElement("view")) { Private::View view; view.file = QUrl(viewElement.attribute("src")); view.windowId = QUuid(viewElement.attribute("window")); view.viewConfig.fromXML(viewElement); d->views.append(view); } //Load session d->profileName.clear(); auto sessionElement = root.firstChildElement("session"); d->profileName = QString(sessionElement.attribute("profile")); } diff --git a/libs/ui/KisSessionResource.h b/libs/ui/KisSessionResource.h index 6ae173bcc7..16527d64ca 100644 --- a/libs/ui/KisSessionResource.h +++ b/libs/ui/KisSessionResource.h @@ -1,46 +1,48 @@ /* * Copyright (c) 2018 Jouni Pentikäinen * * 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 KISSESSIONRESOURCE_H #define KISSESSIONRESOURCE_H #include "KisWindowLayoutResource.h" class KisSessionResource : public KisWindowLayoutResource { public: KisSessionResource(const QString &filename); ~KisSessionResource(); void storeCurrentWindows(); void restore(); QString defaultFileExtension() const override; protected: void saveXml(QDomDocument &doc, QDomElement &root) const override; void loadXml(const QDomElement &root) const override; private: struct Private; QScopedPointer d; }; +typedef QSharedPointer KisSessionResourceSP; + #endif diff --git a/libs/ui/KisViewManager.cpp b/libs/ui/KisViewManager.cpp index 3326872d96..9c57461f1c 100644 --- a/libs/ui/KisViewManager.cpp +++ b/libs/ui/KisViewManager.cpp @@ -1,1409 +1,1409 @@ /* * This file is part of KimageShop^WKrayon^WKrita * * Copyright (c) 1999 Matthias Elter * 1999 Michael Koch * 1999 Carsten Pfeiffer * 2002 Patrick Julien * 2003-2011 Boudewijn Rempt * 2004 Clarence Dang * 2011 José Luis Vergara * 2017 L. E. Segovia * * 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 #include "KisViewManager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "input/kis_input_manager.h" #include "canvas/kis_canvas2.h" #include "canvas/kis_canvas_controller.h" #include "canvas/kis_grid_manager.h" #include "dialogs/kis_dlg_blacklist_cleanup.h" #include "input/kis_input_profile_manager.h" #include "kis_action_manager.h" #include "kis_action.h" #include "kis_canvas_controls_manager.h" #include "kis_canvas_resource_provider.h" #include "kis_composite_progress_proxy.h" #include #include "kis_config.h" #include "kis_config_notifier.h" #include "kis_control_frame.h" #include "kis_coordinates_converter.h" #include "KisDocument.h" #include "kis_favorite_resource_manager.h" #include "kis_filter_manager.h" #include "kis_group_layer.h" #include #include #include "kis_image_manager.h" #include #include "kis_mainwindow_observer.h" #include "kis_mask_manager.h" #include "kis_mimedata.h" #include "kis_mirror_manager.h" #include "kis_node_commands_adapter.h" #include "kis_node.h" #include "kis_node_manager.h" #include "KisDecorationsManager.h" #include #include "kis_paintop_box.h" #include #include "KisPart.h" #include "KisPrintJob.h" #include #include "KisResourceServerProvider.h" #include "kis_selection.h" #include "kis_selection_mask.h" #include "kis_selection_manager.h" #include "kis_shape_controller.h" #include "kis_shape_layer.h" #include #include "kis_statusbar.h" #include #include #include "kis_tooltip_manager.h" #include #include "KisView.h" #include "kis_zoom_manager.h" #include "widgets/kis_floating_message.h" #include "kis_signal_auto_connection.h" #include "kis_icon_utils.h" #include "kis_guides_manager.h" #include "kis_derived_resources.h" #include "dialogs/kis_delayed_save_dialog.h" #include #include "kis_signals_blocker.h" class BlockingUserInputEventFilter : public QObject { bool eventFilter(QObject *watched, QEvent *event) override { Q_UNUSED(watched); if(dynamic_cast(event) || dynamic_cast(event) || dynamic_cast(event)) { return true; } else { return false; } } }; class KisViewManager::KisViewManagerPrivate { public: KisViewManagerPrivate(KisViewManager *_q, KActionCollection *_actionCollection, QWidget *_q_parent) : filterManager(_q) , createTemplate(0) , saveIncremental(0) , saveIncrementalBackup(0) , openResourcesDirectory(0) , rotateCanvasRight(0) , rotateCanvasLeft(0) , resetCanvasRotation(0) , wrapAroundAction(0) , levelOfDetailAction(0) , showRulersAction(0) , rulersTrackMouseAction(0) , zoomTo100pct(0) , zoomIn(0) , zoomOut(0) , selectionManager(_q) , statusBar(_q) , controlFrame(_q, _q_parent) , nodeManager(_q) , imageManager(_q) , gridManager(_q) , canvasControlsManager(_q) , paintingAssistantsManager(_q) , actionManager(_q, _actionCollection) , mainWindow(0) , showFloatingMessage(true) , currentImageView(0) , canvasResourceProvider(_q) , canvasResourceManager() , guiUpdateCompressor(30, KisSignalCompressor::POSTPONE, _q) , actionCollection(_actionCollection) , mirrorManager(_q) , inputManager(_q) , actionAuthor(0) , showPixelGrid(0) { KisViewManager::initializeResourceManager(&canvasResourceManager); } public: KisFilterManager filterManager; KisAction *createTemplate; KisAction *createCopy; KisAction *saveIncremental; KisAction *saveIncrementalBackup; KisAction *openResourcesDirectory; KisAction *rotateCanvasRight; KisAction *rotateCanvasLeft; KisAction *resetCanvasRotation; KisAction *wrapAroundAction; KisAction *levelOfDetailAction; KisAction *showRulersAction; KisAction *rulersTrackMouseAction; KisAction *zoomTo100pct; KisAction *zoomIn; KisAction *zoomOut; KisAction *softProof; KisAction *gamutCheck; KisSelectionManager selectionManager; KisGuidesManager guidesManager; KisStatusBar statusBar; QPointer persistentImageProgressUpdater; QScopedPointer persistentUnthreadedProgressUpdaterRouter; QPointer persistentUnthreadedProgressUpdater; KisControlFrame controlFrame; KisNodeManager nodeManager; KisImageManager imageManager; KisGridManager gridManager; KisCanvasControlsManager canvasControlsManager; KisDecorationsManager paintingAssistantsManager; BlockingUserInputEventFilter blockingEventFilter; KisActionManager actionManager; QMainWindow* mainWindow; QPointer savedFloatingMessage; bool showFloatingMessage; QPointer currentImageView; KisCanvasResourceProvider canvasResourceProvider; KoCanvasResourceProvider canvasResourceManager; KisSignalCompressor guiUpdateCompressor; KActionCollection *actionCollection; KisMirrorManager mirrorManager; KisInputManager inputManager; KisSignalAutoConnectionsStore viewConnections; KSelectAction *actionAuthor; // Select action for author profile. KisAction *showPixelGrid; QByteArray canvasState; #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) QFlags windowFlags; #endif bool blockUntilOperationsFinishedImpl(KisImageSP image, bool force); }; KisViewManager::KisViewManager(QWidget *parent, KActionCollection *_actionCollection) : d(new KisViewManagerPrivate(this, _actionCollection, parent)) { d->actionCollection = _actionCollection; d->mainWindow = dynamic_cast(parent); d->canvasResourceProvider.setResourceManager(&d->canvasResourceManager); connect(&d->guiUpdateCompressor, SIGNAL(timeout()), this, SLOT(guiUpdateTimeout())); createActions(); setupManagers(); // These initialization functions must wait until KisViewManager ctor is complete. d->statusBar.setup(); d->persistentImageProgressUpdater = d->statusBar.progressUpdater()->startSubtask(1, "", true); // reset state to "completed" d->persistentImageProgressUpdater->setRange(0,100); d->persistentImageProgressUpdater->setValue(100); d->persistentUnthreadedProgressUpdater = d->statusBar.progressUpdater()->startSubtask(1, "", true); // reset state to "completed" d->persistentUnthreadedProgressUpdater->setRange(0,100); d->persistentUnthreadedProgressUpdater->setValue(100); d->persistentUnthreadedProgressUpdaterRouter.reset( new KoProgressUpdater(d->persistentUnthreadedProgressUpdater, KoProgressUpdater::Unthreaded)); d->persistentUnthreadedProgressUpdaterRouter->setAutoNestNames(true); d->controlFrame.setup(parent); //Check to draw scrollbars after "Canvas only mode" toggle is created. this->showHideScrollbars(); QScopedPointer dummy(new KoDummyCanvasController(actionCollection())); KoToolManager::instance()->registerToolActions(actionCollection(), dummy.data()); QTimer::singleShot(0, this, SLOT(initializeStatusBarVisibility())); connect(KoToolManager::instance(), SIGNAL(inputDeviceChanged(KoInputDevice)), d->controlFrame.paintopBox(), SLOT(slotInputDeviceChanged(KoInputDevice))); connect(KoToolManager::instance(), SIGNAL(changedTool(KoCanvasController*,int)), d->controlFrame.paintopBox(), SLOT(slotToolChanged(KoCanvasController*,int))); connect(&d->nodeManager, SIGNAL(sigNodeActivated(KisNodeSP)), resourceProvider(), SLOT(slotNodeActivated(KisNodeSP))); connect(KisPart::instance(), SIGNAL(sigViewAdded(KisView*)), SLOT(slotViewAdded(KisView*))); connect(KisPart::instance(), SIGNAL(sigViewRemoved(KisView*)), SLOT(slotViewRemoved(KisView*))); connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotUpdateAuthorProfileActions())); connect(KisConfigNotifier::instance(), SIGNAL(pixelGridModeChanged()), SLOT(slotUpdatePixelGridAction())); KisInputProfileManager::instance()->loadProfiles(); KisConfig cfg(true); d->showFloatingMessage = cfg.showCanvasMessages(); const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8(); KoColor foreground(Qt::black, cs); d->canvasResourceProvider.setFGColor(cfg.readKoColor("LastForeGroundColor",foreground)); KoColor background(Qt::white, cs); d->canvasResourceProvider.setBGColor(cfg.readKoColor("LastBackGroundColor",background)); } KisViewManager::~KisViewManager() { KisConfig cfg(false); if (resourceProvider() && resourceProvider()->currentPreset()) { cfg.writeKoColor("LastForeGroundColor",resourceProvider()->fgColor()); cfg.writeKoColor("LastBackGroundColor",resourceProvider()->bgColor()); } cfg.writeEntry("baseLength", KoResourceItemChooserSync::instance()->baseLength()); delete d; } void KisViewManager::initializeResourceManager(KoCanvasResourceProvider *resourceManager) { resourceManager->addDerivedResourceConverter(toQShared(new KisCompositeOpResourceConverter)); resourceManager->addDerivedResourceConverter(toQShared(new KisEffectiveCompositeOpResourceConverter)); resourceManager->addDerivedResourceConverter(toQShared(new KisOpacityResourceConverter)); resourceManager->addDerivedResourceConverter(toQShared(new KisFlowResourceConverter)); resourceManager->addDerivedResourceConverter(toQShared(new KisSizeResourceConverter)); resourceManager->addDerivedResourceConverter(toQShared(new KisLodAvailabilityResourceConverter)); resourceManager->addDerivedResourceConverter(toQShared(new KisLodSizeThresholdResourceConverter)); resourceManager->addDerivedResourceConverter(toQShared(new KisLodSizeThresholdSupportedResourceConverter)); resourceManager->addDerivedResourceConverter(toQShared(new KisEraserModeResourceConverter)); resourceManager->addResourceUpdateMediator(toQShared(new KisPresetUpdateMediator)); } KActionCollection *KisViewManager::actionCollection() const { return d->actionCollection; } void KisViewManager::slotViewAdded(KisView *view) { // WARNING: this slot is called even when a view from another main windows is added! // Don't expect \p view be a child of this view manager! Q_UNUSED(view); if (viewCount() == 0) { d->statusBar.showAllStatusBarItems(); } } void KisViewManager::slotViewRemoved(KisView *view) { // WARNING: this slot is called even when a view from another main windows is removed! // Don't expect \p view be a child of this view manager! Q_UNUSED(view); if (viewCount() == 0) { d->statusBar.hideAllStatusBarItems(); } KisConfig cfg(false); if (resourceProvider() && resourceProvider()->currentPreset()) { cfg.writeEntry("LastPreset", resourceProvider()->currentPreset()->name()); } } void KisViewManager::setCurrentView(KisView *view) { bool first = true; if (d->currentImageView) { d->currentImageView->notifyCurrentStateChanged(false); d->currentImageView->canvasBase()->setCursor(QCursor(Qt::ArrowCursor)); first = false; KisDocument* doc = d->currentImageView->document(); if (doc) { doc->image()->compositeProgressProxy()->removeProxy(d->persistentImageProgressUpdater); doc->disconnect(this); } d->currentImageView->canvasController()->proxyObject->disconnect(&d->statusBar); d->viewConnections.clear(); } QPointer imageView = qobject_cast(view); d->currentImageView = imageView; if (imageView) { d->softProof->setChecked(imageView->softProofing()); d->gamutCheck->setChecked(imageView->gamutCheck()); // Wait for the async image to have loaded KisDocument* doc = view->document(); if (KisConfig(true).readEntry("EnablePositionLabel", false)) { connect(d->currentImageView->canvasController()->proxyObject, SIGNAL(documentMousePositionChanged(QPointF)), &d->statusBar, SLOT(documentMousePositionChanged(QPointF))); } // Restore the last used brush preset, color and background color. if (first) { KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); QString defaultPresetName = "basic_tip_default"; bool foundTip = false; for (int i=0; iresourceCount(); i++) { KisPaintOpPresetSP resource = rserver->resources().at(i); if (resource->name().toLower().contains("basic_tip_default")) { defaultPresetName = resource->name(); foundTip = true; } else if (foundTip == false && (resource->name().toLower().contains("default") || resource->filename().toLower().contains("default"))) { defaultPresetName = resource->name(); foundTip = true; } } KisConfig cfg(true); QString lastPreset = cfg.readEntry("LastPreset", defaultPresetName); KisPaintOpPresetSP preset = rserver->resourceByName(lastPreset); if (!preset) { preset = rserver->resourceByName(defaultPresetName); } if (!preset && !rserver->resources().isEmpty()) { preset = rserver->resources().first(); } if (preset) { - paintOpBox()->restoreResource(preset.data()); + paintOpBox()->restoreResource(preset); } } KisCanvasController *canvasController = dynamic_cast(d->currentImageView->canvasController()); d->viewConnections.addUniqueConnection(&d->nodeManager, SIGNAL(sigNodeActivated(KisNodeSP)), doc->image(), SLOT(requestStrokeEndActiveNode())); d->viewConnections.addUniqueConnection(d->rotateCanvasRight, SIGNAL(triggered()), canvasController, SLOT(rotateCanvasRight15())); d->viewConnections.addUniqueConnection(d->rotateCanvasLeft, SIGNAL(triggered()),canvasController, SLOT(rotateCanvasLeft15())); d->viewConnections.addUniqueConnection(d->resetCanvasRotation, SIGNAL(triggered()),canvasController, SLOT(resetCanvasRotation())); d->viewConnections.addUniqueConnection(d->wrapAroundAction, SIGNAL(toggled(bool)), canvasController, SLOT(slotToggleWrapAroundMode(bool))); d->wrapAroundAction->setChecked(canvasController->wrapAroundMode()); d->viewConnections.addUniqueConnection(d->levelOfDetailAction, SIGNAL(toggled(bool)), canvasController, SLOT(slotToggleLevelOfDetailMode(bool))); d->levelOfDetailAction->setChecked(canvasController->levelOfDetailMode()); d->viewConnections.addUniqueConnection(d->currentImageView->image(), SIGNAL(sigColorSpaceChanged(const KoColorSpace*)), d->controlFrame.paintopBox(), SLOT(slotColorSpaceChanged(const KoColorSpace*))); d->viewConnections.addUniqueConnection(d->showRulersAction, SIGNAL(toggled(bool)), imageView->zoomManager(), SLOT(setShowRulers(bool))); d->viewConnections.addUniqueConnection(d->rulersTrackMouseAction, SIGNAL(toggled(bool)), imageView->zoomManager(), SLOT(setRulersTrackMouse(bool))); d->viewConnections.addUniqueConnection(d->zoomTo100pct, SIGNAL(triggered()), imageView->zoomManager(), SLOT(zoomTo100())); d->viewConnections.addUniqueConnection(d->zoomIn, SIGNAL(triggered()), imageView->zoomController()->zoomAction(), SLOT(zoomIn())); d->viewConnections.addUniqueConnection(d->zoomOut, SIGNAL(triggered()), imageView->zoomController()->zoomAction(), SLOT(zoomOut())); d->viewConnections.addUniqueConnection(d->softProof, SIGNAL(toggled(bool)), view, SLOT(slotSoftProofing(bool)) ); d->viewConnections.addUniqueConnection(d->gamutCheck, SIGNAL(toggled(bool)), view, SLOT(slotGamutCheck(bool)) ); // set up progrress reporting doc->image()->compositeProgressProxy()->addProxy(d->persistentImageProgressUpdater); d->viewConnections.addUniqueConnection(&d->statusBar, SIGNAL(sigCancellationRequested()), doc->image(), SLOT(requestStrokeCancellation())); d->viewConnections.addUniqueConnection(d->showPixelGrid, SIGNAL(toggled(bool)), canvasController, SLOT(slotTogglePixelGrid(bool))); imageView->zoomManager()->setShowRulers(d->showRulersAction->isChecked()); imageView->zoomManager()->setRulersTrackMouse(d->rulersTrackMouseAction->isChecked()); showHideScrollbars(); } d->filterManager.setView(imageView); d->selectionManager.setView(imageView); d->guidesManager.setView(imageView); d->nodeManager.setView(imageView); d->imageManager.setView(imageView); d->canvasControlsManager.setView(imageView); d->actionManager.setView(imageView); d->gridManager.setView(imageView); d->statusBar.setView(imageView); d->paintingAssistantsManager.setView(imageView); d->mirrorManager.setView(imageView); if (d->currentImageView) { d->currentImageView->notifyCurrentStateChanged(true); d->currentImageView->canvasController()->activate(); d->currentImageView->canvasController()->setFocus(); d->viewConnections.addUniqueConnection( image(), SIGNAL(sigSizeChanged(QPointF,QPointF)), resourceProvider(), SLOT(slotImageSizeChanged())); d->viewConnections.addUniqueConnection( image(), SIGNAL(sigResolutionChanged(double,double)), resourceProvider(), SLOT(slotOnScreenResolutionChanged())); d->viewConnections.addUniqueConnection( image(), SIGNAL(sigNodeChanged(KisNodeSP)), this, SLOT(updateGUI())); d->viewConnections.addUniqueConnection( d->currentImageView->zoomManager()->zoomController(), SIGNAL(zoomChanged(KoZoomMode::Mode,qreal)), resourceProvider(), SLOT(slotOnScreenResolutionChanged())); } d->actionManager.updateGUI(); resourceProvider()->slotImageSizeChanged(); resourceProvider()->slotOnScreenResolutionChanged(); Q_EMIT viewChanged(); } KoZoomController *KisViewManager::zoomController() const { if (d->currentImageView) { return d->currentImageView->zoomController(); } return 0; } KisImageWSP KisViewManager::image() const { if (document()) { return document()->image(); } return 0; } KisCanvasResourceProvider * KisViewManager::resourceProvider() { return &d->canvasResourceProvider; } KisCanvas2 * KisViewManager::canvasBase() const { if (d && d->currentImageView) { return d->currentImageView->canvasBase(); } return 0; } QWidget* KisViewManager::canvas() const { if (d && d->currentImageView && d->currentImageView->canvasBase()->canvasWidget()) { return d->currentImageView->canvasBase()->canvasWidget(); } return 0; } KisStatusBar * KisViewManager::statusBar() const { return &d->statusBar; } KisPaintopBox* KisViewManager::paintOpBox() const { return d->controlFrame.paintopBox(); } QPointer KisViewManager::createUnthreadedUpdater(const QString &name) { return d->persistentUnthreadedProgressUpdaterRouter->startSubtask(1, name, false); } QPointer KisViewManager::createThreadedUpdater(const QString &name) { return d->statusBar.progressUpdater()->startSubtask(1, name, false); } KisSelectionManager * KisViewManager::selectionManager() { return &d->selectionManager; } KisNodeSP KisViewManager::activeNode() { return d->nodeManager.activeNode(); } KisLayerSP KisViewManager::activeLayer() { return d->nodeManager.activeLayer(); } KisPaintDeviceSP KisViewManager::activeDevice() { return d->nodeManager.activePaintDevice(); } KisZoomManager * KisViewManager::zoomManager() { if (d->currentImageView) { return d->currentImageView->zoomManager(); } return 0; } KisFilterManager * KisViewManager::filterManager() { return &d->filterManager; } KisImageManager * KisViewManager::imageManager() { return &d->imageManager; } KisInputManager* KisViewManager::inputManager() const { return &d->inputManager; } KisSelectionSP KisViewManager::selection() { if (d->currentImageView) { return d->currentImageView->selection(); } return 0; } bool KisViewManager::selectionEditable() { KisLayerSP layer = activeLayer(); if (layer) { KisSelectionMaskSP mask = layer->selectionMask(); if (mask) { return mask->isEditable(); } } // global selection is always editable return true; } KisUndoAdapter * KisViewManager::undoAdapter() { if (!document()) return 0; KisImageWSP image = document()->image(); Q_ASSERT(image); return image->undoAdapter(); } void KisViewManager::createActions() { KisConfig cfg(true); d->saveIncremental = actionManager()->createAction("save_incremental_version"); connect(d->saveIncremental, SIGNAL(triggered()), this, SLOT(slotSaveIncremental())); d->saveIncrementalBackup = actionManager()->createAction("save_incremental_backup"); connect(d->saveIncrementalBackup, SIGNAL(triggered()), this, SLOT(slotSaveIncrementalBackup())); connect(mainWindow(), SIGNAL(documentSaved()), this, SLOT(slotDocumentSaved())); d->saveIncremental->setEnabled(false); d->saveIncrementalBackup->setEnabled(false); KisAction *tabletDebugger = actionManager()->createAction("tablet_debugger"); connect(tabletDebugger, SIGNAL(triggered()), this, SLOT(toggleTabletLogger())); d->createTemplate = actionManager()->createAction("create_template"); connect(d->createTemplate, SIGNAL(triggered()), this, SLOT(slotCreateTemplate())); d->createCopy = actionManager()->createAction("create_copy"); connect(d->createCopy, SIGNAL(triggered()), this, SLOT(slotCreateCopy())); d->openResourcesDirectory = actionManager()->createAction("open_resources_directory"); connect(d->openResourcesDirectory, SIGNAL(triggered()), SLOT(openResourcesDirectory())); d->rotateCanvasRight = actionManager()->createAction("rotate_canvas_right"); d->rotateCanvasLeft = actionManager()->createAction("rotate_canvas_left"); d->resetCanvasRotation = actionManager()->createAction("reset_canvas_rotation"); d->wrapAroundAction = actionManager()->createAction("wrap_around_mode"); d->levelOfDetailAction = actionManager()->createAction("level_of_detail_mode"); d->softProof = actionManager()->createAction("softProof"); d->gamutCheck = actionManager()->createAction("gamutCheck"); KisAction *tAction = actionManager()->createAction("showStatusBar"); tAction->setChecked(cfg.showStatusBar()); connect(tAction, SIGNAL(toggled(bool)), this, SLOT(showStatusBar(bool))); tAction = actionManager()->createAction("view_show_canvas_only"); tAction->setChecked(false); connect(tAction, SIGNAL(toggled(bool)), this, SLOT(switchCanvasOnly(bool))); //Workaround, by default has the same shortcut as mirrorCanvas KisAction *a = dynamic_cast(actionCollection()->action("format_italic")); if (a) { a->setDefaultShortcut(QKeySequence()); } a = actionManager()->createAction("edit_blacklist_cleanup"); connect(a, SIGNAL(triggered()), this, SLOT(slotBlacklistCleanup())); actionManager()->createAction("ruler_pixel_multiple2"); d->showRulersAction = actionManager()->createAction("view_ruler"); d->showRulersAction->setChecked(cfg.showRulers()); connect(d->showRulersAction, SIGNAL(toggled(bool)), SLOT(slotSaveShowRulersState(bool))); d->rulersTrackMouseAction = actionManager()->createAction("rulers_track_mouse"); d->rulersTrackMouseAction->setChecked(cfg.rulersTrackMouse()); connect(d->rulersTrackMouseAction, SIGNAL(toggled(bool)), SLOT(slotSaveRulersTrackMouseState(bool))); d->zoomTo100pct = actionManager()->createAction("zoom_to_100pct"); d->zoomIn = actionManager()->createStandardAction(KStandardAction::ZoomIn, 0, ""); d->zoomOut = actionManager()->createStandardAction(KStandardAction::ZoomOut, 0, ""); d->actionAuthor = new KSelectAction(KisIconUtils::loadIcon("im-user"), i18n("Active Author Profile"), this); connect(d->actionAuthor, SIGNAL(triggered(QString)), this, SLOT(changeAuthorProfile(QString))); actionCollection()->addAction("settings_active_author", d->actionAuthor); slotUpdateAuthorProfileActions(); d->showPixelGrid = actionManager()->createAction("view_pixel_grid"); slotUpdatePixelGridAction(); } void KisViewManager::setupManagers() { // Create the managers for filters, selections, layers etc. // XXX: When the currentlayer changes, call updateGUI on all // managers d->filterManager.setup(actionCollection(), actionManager()); d->selectionManager.setup(actionManager()); d->guidesManager.setup(actionManager()); d->nodeManager.setup(actionCollection(), actionManager()); d->imageManager.setup(actionManager()); d->gridManager.setup(actionManager()); d->paintingAssistantsManager.setup(actionManager()); d->canvasControlsManager.setup(actionManager()); d->mirrorManager.setup(actionCollection()); } void KisViewManager::updateGUI() { d->guiUpdateCompressor.start(); } void KisViewManager::slotBlacklistCleanup() { KisDlgBlacklistCleanup dialog; dialog.exec(); } KisNodeManager * KisViewManager::nodeManager() const { return &d->nodeManager; } KisActionManager* KisViewManager::actionManager() const { return &d->actionManager; } KisGridManager * KisViewManager::gridManager() const { return &d->gridManager; } KisGuidesManager * KisViewManager::guidesManager() const { return &d->guidesManager; } KisDocument *KisViewManager::document() const { if (d->currentImageView && d->currentImageView->document()) { return d->currentImageView->document(); } return 0; } int KisViewManager::viewCount() const { KisMainWindow *mw = qobject_cast(d->mainWindow); if (mw) { return mw->viewCount(); } return 0; } bool KisViewManager::KisViewManagerPrivate::blockUntilOperationsFinishedImpl(KisImageSP image, bool force) { const int busyWaitDelay = 1000; KisDelayedSaveDialog dialog(image, !force ? KisDelayedSaveDialog::GeneralDialog : KisDelayedSaveDialog::ForcedDialog, busyWaitDelay, mainWindow); dialog.blockIfImageIsBusy(); return dialog.result() == QDialog::Accepted; } bool KisViewManager::blockUntilOperationsFinished(KisImageSP image) { return d->blockUntilOperationsFinishedImpl(image, false); } void KisViewManager::blockUntilOperationsFinishedForced(KisImageSP image) { d->blockUntilOperationsFinishedImpl(image, true); } void KisViewManager::slotCreateTemplate() { if (!document()) return; KisTemplateCreateDia::createTemplate( QStringLiteral("templates/"), ".kra", document(), mainWindow()); } void KisViewManager::slotCreateCopy() { KisDocument *srcDoc = document(); if (!srcDoc) return; if (!this->blockUntilOperationsFinished(srcDoc->image())) return; KisDocument *doc = 0; { KisImageBarrierLocker l(srcDoc->image()); doc = srcDoc->clone(); } KIS_SAFE_ASSERT_RECOVER_RETURN(doc); QString name = srcDoc->documentInfo()->aboutInfo("name"); if (name.isEmpty()) { name = document()->url().toLocalFile(); } name = i18n("%1 (Copy)", name); doc->documentInfo()->setAboutInfo("title", name); KisPart::instance()->addDocument(doc); KisMainWindow *mw = qobject_cast(d->mainWindow); mw->addViewAndNotifyLoadingCompleted(doc); } QMainWindow* KisViewManager::qtMainWindow() const { if (d->mainWindow) return d->mainWindow; //Fallback for when we have not yet set the main window. QMainWindow* w = qobject_cast(qApp->activeWindow()); if(w) return w; return mainWindow(); } void KisViewManager::setQtMainWindow(QMainWindow* newMainWindow) { d->mainWindow = newMainWindow; } void KisViewManager::slotDocumentSaved() { d->saveIncremental->setEnabled(true); d->saveIncrementalBackup->setEnabled(true); } void KisViewManager::slotSaveIncremental() { if (!document()) return; if (document()->url().isEmpty()) { KisMainWindow *mw = qobject_cast(d->mainWindow); mw->saveDocument(document(), true, false); return; } bool foundVersion; bool fileAlreadyExists; bool isBackup; QString version = "000"; QString newVersion; QString letter; QString fileName = document()->localFilePath(); // Find current version filenames // v v Regexp to find incremental versions in the filename, taking our backup scheme into account as well // Considering our incremental version and backup scheme, format is filename_001~001.ext QRegExp regex("_\\d{1,4}[.]|_\\d{1,4}[a-z][.]|_\\d{1,4}[~]|_\\d{1,4}[a-z][~]"); regex.indexIn(fileName); // Perform the search QStringList matches = regex.capturedTexts(); foundVersion = matches.at(0).isEmpty() ? false : true; // Ensure compatibility with Save Incremental Backup // If this regex is not kept separate, the entire algorithm needs modification; // It's simpler to just add this. QRegExp regexAux("_\\d{1,4}[~]|_\\d{1,4}[a-z][~]"); regexAux.indexIn(fileName); // Perform the search QStringList matchesAux = regexAux.capturedTexts(); isBackup = matchesAux.at(0).isEmpty() ? false : true; // If the filename has a version, prepare it for incrementation if (foundVersion) { version = matches.at(matches.count() - 1); // Look at the last index, we don't care about other matches if (version.contains(QRegExp("[a-z]"))) { version.chop(1); // Trim "." letter = version.right(1); // Save letter version.chop(1); // Trim letter } else { version.chop(1); // Trim "." } version.remove(0, 1); // Trim "_" } else { // TODO: this will not work with files extensions like jp2 // ...else, simply add a version to it so the next loop works QRegExp regex2("[.][a-z]{2,4}$"); // Heuristic to find file extension regex2.indexIn(fileName); QStringList matches2 = regex2.capturedTexts(); QString extensionPlusVersion = matches2.at(0); extensionPlusVersion.prepend(version); extensionPlusVersion.prepend("_"); fileName.replace(regex2, extensionPlusVersion); } // Prepare the base for new version filename int intVersion = version.toInt(0); ++intVersion; QString baseNewVersion = QString::number(intVersion); while (baseNewVersion.length() < version.length()) { baseNewVersion.prepend("0"); } // Check if the file exists under the new name and search until options are exhausted (test appending a to z) do { newVersion = baseNewVersion; newVersion.prepend("_"); if (!letter.isNull()) newVersion.append(letter); if (isBackup) { newVersion.append("~"); } else { newVersion.append("."); } fileName.replace(regex, newVersion); fileAlreadyExists = QFile(fileName).exists(); if (fileAlreadyExists) { if (!letter.isNull()) { char letterCh = letter.at(0).toLatin1(); ++letterCh; letter = QString(QChar(letterCh)); } else { letter = 'a'; } } } while (fileAlreadyExists && letter != "{"); // x, y, z, {... if (letter == "{") { QMessageBox::critical(mainWindow(), i18nc("@title:window", "Couldn't save incremental version"), i18n("Alternative names exhausted, try manually saving with a higher number")); return; } document()->setFileBatchMode(true); document()->saveAs(QUrl::fromUserInput(fileName), document()->mimeType(), true); document()->setFileBatchMode(false); if (mainWindow()) { mainWindow()->updateCaption(); } } void KisViewManager::slotSaveIncrementalBackup() { if (!document()) return; if (document()->url().isEmpty()) { KisMainWindow *mw = qobject_cast(d->mainWindow); mw->saveDocument(document(), true, false); return; } bool workingOnBackup; bool fileAlreadyExists; QString version = "000"; QString newVersion; QString letter; QString fileName = document()->localFilePath(); // First, discover if working on a backup file, or a normal file QRegExp regex("~\\d{1,4}[.]|~\\d{1,4}[a-z][.]"); regex.indexIn(fileName); // Perform the search QStringList matches = regex.capturedTexts(); workingOnBackup = matches.at(0).isEmpty() ? false : true; if (workingOnBackup) { // Try to save incremental version (of backup), use letter for alt versions version = matches.at(matches.count() - 1); // Look at the last index, we don't care about other matches if (version.contains(QRegExp("[a-z]"))) { version.chop(1); // Trim "." letter = version.right(1); // Save letter version.chop(1); // Trim letter } else { version.chop(1); // Trim "." } version.remove(0, 1); // Trim "~" // Prepare the base for new version filename int intVersion = version.toInt(0); ++intVersion; QString baseNewVersion = QString::number(intVersion); QString backupFileName = document()->localFilePath(); while (baseNewVersion.length() < version.length()) { baseNewVersion.prepend("0"); } // Check if the file exists under the new name and search until options are exhausted (test appending a to z) do { newVersion = baseNewVersion; newVersion.prepend("~"); if (!letter.isNull()) newVersion.append(letter); newVersion.append("."); backupFileName.replace(regex, newVersion); fileAlreadyExists = QFile(backupFileName).exists(); if (fileAlreadyExists) { if (!letter.isNull()) { char letterCh = letter.at(0).toLatin1(); ++letterCh; letter = QString(QChar(letterCh)); } else { letter = 'a'; } } } while (fileAlreadyExists && letter != "{"); // x, y, z, {... if (letter == "{") { QMessageBox::critical(mainWindow(), i18nc("@title:window", "Couldn't save incremental backup"), i18n("Alternative names exhausted, try manually saving with a higher number")); return; } QFile::copy(fileName, backupFileName); document()->saveAs(QUrl::fromUserInput(fileName), document()->mimeType(), true); if (mainWindow()) mainWindow()->updateCaption(); } else { // if NOT working on a backup... // Navigate directory searching for latest backup version, ignore letters const quint8 HARDCODED_DIGIT_COUNT = 3; QString baseNewVersion = "000"; QString backupFileName = document()->localFilePath(); QRegExp regex2("[.][a-z]{2,4}$"); // Heuristic to find file extension regex2.indexIn(backupFileName); QStringList matches2 = regex2.capturedTexts(); QString extensionPlusVersion = matches2.at(0); extensionPlusVersion.prepend(baseNewVersion); extensionPlusVersion.prepend("~"); backupFileName.replace(regex2, extensionPlusVersion); // Save version with 1 number higher than the highest version found ignoring letters do { newVersion = baseNewVersion; newVersion.prepend("~"); newVersion.append("."); backupFileName.replace(regex, newVersion); fileAlreadyExists = QFile(backupFileName).exists(); if (fileAlreadyExists) { // Prepare the base for new version filename, increment by 1 int intVersion = baseNewVersion.toInt(0); ++intVersion; baseNewVersion = QString::number(intVersion); while (baseNewVersion.length() < HARDCODED_DIGIT_COUNT) { baseNewVersion.prepend("0"); } } } while (fileAlreadyExists); // Save both as backup and on current file for interapplication workflow document()->setFileBatchMode(true); QFile::copy(fileName, backupFileName); document()->saveAs(QUrl::fromUserInput(fileName), document()->mimeType(), true); document()->setFileBatchMode(false); if (mainWindow()) mainWindow()->updateCaption(); } } void KisViewManager::disableControls() { // prevents possible crashes, if somebody changes the paintop during dragging by using the mousewheel // this is for Bug 250944 // the solution blocks all wheel, mouse and key event, while dragging with the freehand tool // see KisToolFreehand::initPaint() and endPaint() d->controlFrame.paintopBox()->installEventFilter(&d->blockingEventFilter); Q_FOREACH (QObject* child, d->controlFrame.paintopBox()->children()) { child->installEventFilter(&d->blockingEventFilter); } } void KisViewManager::enableControls() { d->controlFrame.paintopBox()->removeEventFilter(&d->blockingEventFilter); Q_FOREACH (QObject* child, d->controlFrame.paintopBox()->children()) { child->removeEventFilter(&d->blockingEventFilter); } } void KisViewManager::showStatusBar(bool toggled) { KisMainWindow *mw = mainWindow(); if(mw && mw->statusBar()) { mw->statusBar()->setVisible(toggled); KisConfig cfg(false); cfg.setShowStatusBar(toggled); } } void KisViewManager::switchCanvasOnly(bool toggled) { KisConfig cfg(false); KisMainWindow* main = mainWindow(); if(!main) { dbgUI << "Unable to switch to canvas-only mode, main window not found"; return; } if (toggled) { d->canvasState = qtMainWindow()->saveState(); #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) d->windowFlags = main->windowState(); #endif } if (cfg.hideStatusbarFullscreen()) { if (main->statusBar()) { if (!toggled) { if (main->statusBar()->dynamicPropertyNames().contains("wasvisible")) { if (main->statusBar()->property("wasvisible").toBool()) { main->statusBar()->setVisible(true); } } } else { main->statusBar()->setProperty("wasvisible", main->statusBar()->isVisible()); main->statusBar()->setVisible(false); } } } if (cfg.hideDockersFullscreen()) { KisAction* action = qobject_cast(main->actionCollection()->action("view_toggledockers")); if (action) { action->setCheckable(true); if (toggled) { if (action->isChecked()) { cfg.setShowDockers(action->isChecked()); action->setChecked(false); } else { cfg.setShowDockers(false); } } else { action->setChecked(cfg.showDockers()); } } } // QT in windows does not return to maximized upon 4th tab in a row // https://bugreports.qt.io/browse/QTBUG-57882, https://bugreports.qt.io/browse/QTBUG-52555, https://codereview.qt-project.org/#/c/185016/ if (cfg.hideTitlebarFullscreen() && !cfg.fullscreenMode()) { if(toggled) { main->setWindowState( main->windowState() | Qt::WindowFullScreen); } else { main->setWindowState( main->windowState() & ~Qt::WindowFullScreen); #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) // If window was maximized prior to fullscreen, restore that if (d->windowFlags & Qt::WindowMaximized) { main->setWindowState( main->windowState() | Qt::WindowMaximized); } #endif } } if (cfg.hideMenuFullscreen()) { if (!toggled) { if (main->menuBar()->dynamicPropertyNames().contains("wasvisible")) { if (main->menuBar()->property("wasvisible").toBool()) { main->menuBar()->setVisible(true); } } } else { main->menuBar()->setProperty("wasvisible", main->menuBar()->isVisible()); main->menuBar()->setVisible(false); } } if (cfg.hideToolbarFullscreen()) { QList toolBars = main->findChildren(); Q_FOREACH (QToolBar* toolbar, toolBars) { if (!toggled) { if (toolbar->dynamicPropertyNames().contains("wasvisible")) { if (toolbar->property("wasvisible").toBool()) { toolbar->setVisible(true); } } } else { toolbar->setProperty("wasvisible", toolbar->isVisible()); toolbar->setVisible(false); } } } showHideScrollbars(); if (toggled) { // show a fading heads-up display about the shortcut to go back showFloatingMessage(i18n("Going into Canvas-Only mode.\nPress %1 to go back.", actionCollection()->action("view_show_canvas_only")->shortcut().toString()), QIcon()); } else { main->restoreState(d->canvasState); } } void KisViewManager::toggleTabletLogger() { d->inputManager.toggleTabletLogger(); } void KisViewManager::openResourcesDirectory() { QString dir = KoResourcePaths::locateLocal("data", ""); QDesktopServices::openUrl(QUrl::fromLocalFile(dir)); } void KisViewManager::updateIcons() { if (mainWindow()) { QList dockers = mainWindow()->dockWidgets(); Q_FOREACH (QDockWidget* dock, dockers) { QObjectList objects; objects.append(dock); while (!objects.isEmpty()) { QObject* object = objects.takeFirst(); objects.append(object->children()); KisIconUtils::updateIconCommon(object); } } } } void KisViewManager::initializeStatusBarVisibility() { KisConfig cfg(true); d->mainWindow->statusBar()->setVisible(cfg.showStatusBar()); } void KisViewManager::guiUpdateTimeout() { d->nodeManager.updateGUI(); d->selectionManager.updateGUI(); d->filterManager.updateGUI(); if (zoomManager()) { zoomManager()->updateGUI(); } d->gridManager.updateGUI(); d->actionManager.updateGUI(); } void KisViewManager::showFloatingMessage(const QString &message, const QIcon& icon, int timeout, KisFloatingMessage::Priority priority, int alignment) { if (!d->currentImageView) return; d->currentImageView->showFloatingMessage(message, icon, timeout, priority, alignment); emit floatingMessageRequested(message, icon.name()); } KisMainWindow *KisViewManager::mainWindow() const { return qobject_cast(d->mainWindow); } void KisViewManager::showHideScrollbars() { if (!d->currentImageView) return; if (!d->currentImageView->canvasController()) return; KisConfig cfg(true); bool toggled = actionCollection()->action("view_show_canvas_only")->isChecked(); if ( (toggled && cfg.hideScrollbarsFullscreen()) || (!toggled && cfg.hideScrollbars()) ) { d->currentImageView->canvasController()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); d->currentImageView->canvasController()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); } else { d->currentImageView->canvasController()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); d->currentImageView->canvasController()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); } } void KisViewManager::slotSaveShowRulersState(bool value) { KisConfig cfg(false); cfg.setShowRulers(value); } void KisViewManager::slotSaveRulersTrackMouseState(bool value) { KisConfig cfg(false); cfg.setRulersTrackMouse(value); } void KisViewManager::setShowFloatingMessage(bool show) { d->showFloatingMessage = show; } void KisViewManager::changeAuthorProfile(const QString &profileName) { KConfigGroup appAuthorGroup(KSharedConfig::openConfig(), "Author"); if (profileName.isEmpty() || profileName == i18nc("choice for author profile", "Anonymous")) { appAuthorGroup.writeEntry("active-profile", ""); } else { appAuthorGroup.writeEntry("active-profile", profileName); } appAuthorGroup.sync(); Q_FOREACH (KisDocument *doc, KisPart::instance()->documents()) { doc->documentInfo()->updateParameters(); } } void KisViewManager::slotUpdateAuthorProfileActions() { Q_ASSERT(d->actionAuthor); if (!d->actionAuthor) { return; } d->actionAuthor->clear(); d->actionAuthor->addAction(i18nc("choice for author profile", "Anonymous")); KConfigGroup authorGroup(KSharedConfig::openConfig(), "Author"); QStringList profiles = authorGroup.readEntry("profile-names", QStringList()); QString authorInfo = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/authorinfo/"; QStringList filters = QStringList() << "*.authorinfo"; QDir dir(authorInfo); Q_FOREACH(QString entry, dir.entryList(filters)) { int ln = QString(".authorinfo").size(); entry.chop(ln); if (!profiles.contains(entry)) { profiles.append(entry); } } Q_FOREACH (const QString &profile , profiles) { d->actionAuthor->addAction(profile); } KConfigGroup appAuthorGroup(KSharedConfig::openConfig(), "Author"); QString profileName = appAuthorGroup.readEntry("active-profile", ""); if (profileName == "anonymous" || profileName.isEmpty()) { d->actionAuthor->setCurrentItem(0); } else if (profiles.contains(profileName)) { d->actionAuthor->setCurrentAction(profileName); } } void KisViewManager::slotUpdatePixelGridAction() { KIS_SAFE_ASSERT_RECOVER_RETURN(d->showPixelGrid); KisSignalsBlocker b(d->showPixelGrid); KisConfig cfg(true); d->showPixelGrid->setChecked(cfg.pixelGridEnabled() && cfg.useOpenGL()); } void KisViewManager::slotActivateTransformTool() { if(KoToolManager::instance()->activeToolId() == "KisToolTransform") { KoToolBase* tool = KoToolManager::instance()->toolById(canvasBase(), "KisToolTransform"); QSet dummy; // Start a new stroke tool->deactivate(); tool->activate(KoToolBase::DefaultActivation, dummy); } KoToolManager::instance()->switchToolRequested("KisToolTransform"); } diff --git a/libs/ui/KisWindowLayoutManager.cpp b/libs/ui/KisWindowLayoutManager.cpp index 26e7ccdc58..054855501d 100644 --- a/libs/ui/KisWindowLayoutManager.cpp +++ b/libs/ui/KisWindowLayoutManager.cpp @@ -1,243 +1,243 @@ /* * Copyright (c) 2018 Jouni Pentikäinen * * 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 "KisWindowLayoutManager.h" #include #include #include #include #include #include #include #include #include #include #include Q_GLOBAL_STATIC(KisWindowLayoutManager, s_instance) struct KisWindowLayoutManager::Private { bool showImageInAllWindows{false}; bool primaryWorkspaceFollowsFocus{false}; QUuid primaryWindow; QVector displayLayouts; void loadDisplayLayouts() { KConfigGroup layoutsCfg(KSharedConfig::openConfig(), "DisplayLayouts"); QStringList groups = layoutsCfg.groupList(); Q_FOREACH(QString name, groups) { loadDisplayLayout(name, layoutsCfg.group(name)); } } void loadDisplayLayout(const QString &name, KConfigGroup layoutCfg) { DisplayLayout *layout = new DisplayLayout(); layout->name = name; int displayNumber = 1; while (true) { const QString displayDefinition = layoutCfg.readEntry(QString("Display%1").arg(displayNumber++), QString()); if (displayDefinition.isEmpty()) break; // Just the resolution for now. Later we might want to split by a separator and include things like serial number, etc. const QString &resolutionStr = displayDefinition; QStringList dimensions = resolutionStr.split('x'); if (dimensions.size() != 2) { qWarning() << "Invalid display definition: " << displayDefinition; break; } QSize resolution = QSize( KisDomUtils::toInt(dimensions[0]), KisDomUtils::toInt(dimensions[1]) ); layout->displays.append(Display{resolution}); } layout->preferredWindowLayout = layoutCfg.readEntry("PreferredLayout", ""); displayLayouts.append(layout); } void saveDisplayLayout(const DisplayLayout &layout) { KConfigGroup layoutsCfg(KSharedConfig::openConfig(), "DisplayLayouts"); KConfigGroup layoutCfg = layoutsCfg.group(layout.name); layoutCfg.writeEntry("PreferredLayout", layout.preferredWindowLayout); } }; bool KisWindowLayoutManager::Display::matches(QScreen* screen) const { return resolution == screen->geometry().size(); } bool KisWindowLayoutManager::DisplayLayout::matches(QList screens) const { if (screens.size() != displays.size()) return false; QVector matchedScreens(screens.size()); Q_FOREACH(auto &expectedDisplay, displays) { int i; for (i = 0; i < screens.size(); i++) { if (matchedScreens[i]) continue; if (expectedDisplay.matches(screens[i])) { matchedScreens[i] = true; break; } } if (i == screens.size()) { return false; } } return true; } KisWindowLayoutManager * KisWindowLayoutManager::instance() { return s_instance; } KisWindowLayoutManager::KisWindowLayoutManager() : d(new Private) { d->loadDisplayLayouts(); connect(qobject_cast(KisApplication::instance()), SIGNAL(focusChanged(QWidget*,QWidget*)), this, SLOT(slotFocusChanged(QWidget*,QWidget*))); connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(slotScreensChanged())); connect(QApplication::desktop(), SIGNAL(screenCountChanged(int)), this, SLOT(slotScreensChanged())); } KisWindowLayoutManager::~KisWindowLayoutManager() { Q_FOREACH(DisplayLayout *layout, d->displayLayouts) { delete layout; } } void KisWindowLayoutManager::setShowImageInAllWindowsEnabled(bool showInAll) { bool wasEnabled = d->showImageInAllWindows; d->showImageInAllWindows = showInAll; if (!wasEnabled && showInAll) { KisMainWindow *currentMainWindow = KisPart::instance()->currentMainwindow(); if (currentMainWindow) { KisView *activeView = currentMainWindow->activeView(); if (activeView) { KisDocument *document = activeView->document(); if (document) { activeDocumentChanged(document); } } } } } bool KisWindowLayoutManager::isShowImageInAllWindowsEnabled() const { return d->showImageInAllWindows; } bool KisWindowLayoutManager::primaryWorkspaceFollowsFocus() const { return d->primaryWorkspaceFollowsFocus; } void KisWindowLayoutManager::setPrimaryWorkspaceFollowsFocus(bool enabled, QUuid primaryWindow) { d->primaryWorkspaceFollowsFocus = enabled; d->primaryWindow = primaryWindow; } QUuid KisWindowLayoutManager::primaryWindowId() const { return d->primaryWindow; } void KisWindowLayoutManager::activeDocumentChanged(KisDocument *document) { if (d->showImageInAllWindows) { Q_FOREACH(QPointer window, KisPart::instance()->mainWindows()) { if (window->isHidden()) continue; const auto view = window->activeView(); if (!view || view->document() != document) { window->showDocument(document); } } } } void KisWindowLayoutManager::slotFocusChanged(QWidget *old, QWidget *now) { Q_UNUSED(old); if (!now) return; KisMainWindow *newMainWindow = qobject_cast(now->window()); if (!newMainWindow) return; newMainWindow->windowFocused(); } -void KisWindowLayoutManager::setLastUsedLayout(const KisWindowLayoutResource *layout) +void KisWindowLayoutManager::setLastUsedLayout(KisWindowLayoutResourceSP layout) { // For automatic switching, only allow a window layout proper - auto *session = dynamic_cast(layout); + KisSessionResourceSP session = layout.dynamicCast(); if (session) return; QList screens = QGuiApplication::screens(); Q_FOREACH(DisplayLayout *displayLayout, d->displayLayouts) { if (displayLayout->matches(screens)) { displayLayout->preferredWindowLayout = layout->name(); d->saveDisplayLayout(*displayLayout); break; } } } void KisWindowLayoutManager::slotScreensChanged() { QList screens = QGuiApplication::screens(); Q_FOREACH(const DisplayLayout *displayLayout, d->displayLayouts) { if (displayLayout->matches(screens)) { KoResourceServer *windowLayoutServer = KisResourceServerProvider::instance()->windowLayoutServer(); - KisWindowLayoutResource *layout = windowLayoutServer->resourceByName(displayLayout->preferredWindowLayout); + KisWindowLayoutResourceSP layout = windowLayoutServer->resourceByName(displayLayout->preferredWindowLayout); if (layout) { setLastUsedLayout(layout); layout->applyLayout(); return; } } } } diff --git a/libs/ui/KisWindowLayoutManager.h b/libs/ui/KisWindowLayoutManager.h index eb7ae94029..075a5ebda3 100644 --- a/libs/ui/KisWindowLayoutManager.h +++ b/libs/ui/KisWindowLayoutManager.h @@ -1,85 +1,86 @@ /* * Copyright (c) 2018 Jouni Pentikäinen * * 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 KISWINDOWLAYOUTMANAGER_H #define KISWINDOWLAYOUTMANAGER_H #include #include #include #include +#include + class QScreen; -class KisWindowLayoutResource; class KisDocument; class KisWindowLayoutManager : public QObject { Q_OBJECT public: struct Display { QSize resolution; bool matches(QScreen* screen) const; }; struct DisplayLayout { QString name; QVector displays; QString preferredWindowLayout; bool matches(QList screens) const; }; explicit KisWindowLayoutManager(); ~KisWindowLayoutManager(); static KisWindowLayoutManager *instance(); /** * When enabled, a workspace dedicated as primary is used for any main window which receives focus. * Meanwhile, the workspace of that window is used for the window which originally had the primary workspace. */ bool primaryWorkspaceFollowsFocus() const; void setPrimaryWorkspaceFollowsFocus(bool enabled, QUuid primaryWindow); QUuid primaryWindowId() const; /** * When enabled, main windows will synchronize to keep the same document active */ bool isShowImageInAllWindowsEnabled() const; void setShowImageInAllWindowsEnabled(bool showInAll); void activeDocumentChanged(KisDocument *document); - void setLastUsedLayout(const KisWindowLayoutResource *layout); + void setLastUsedLayout(KisWindowLayoutResourceSP layout); private Q_SLOTS: void slotFocusChanged(QWidget*, QWidget*); void slotScreensChanged(); private: struct Private; QScopedPointer d; }; #endif diff --git a/libs/ui/KisWindowLayoutResource.cpp b/libs/ui/KisWindowLayoutResource.cpp index 1f182c59b1..ee0308bfd9 100644 --- a/libs/ui/KisWindowLayoutResource.cpp +++ b/libs/ui/KisWindowLayoutResource.cpp @@ -1,387 +1,387 @@ /* * Copyright (c) 2018 Jouni Pentikäinen * * 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 "KisWindowLayoutResource.h" #include "KisWindowLayoutManager.h" #include #include #include #include #include #include #include #include #include #include #include static const int WINDOW_LAYOUT_VERSION = 1; struct KisWindowLayoutResource::Private { struct Window { QUuid windowId; QByteArray geometry; QByteArray windowState; int screen = -1; Qt::WindowStates stateFlags = Qt::WindowNoState; }; QVector windows; bool showImageInAllWindows; bool primaryWorkspaceFollowsFocus; QUuid primaryWindow; Private() = default; explicit Private(QVector windows) : windows(std::move(windows)) {} void openNecessaryWindows(QList> ¤tWindows) { auto *kisPart = KisPart::instance(); Q_FOREACH(const Window &window, windows) { QPointer mainWindow = kisPart->windowById(window.windowId); if (mainWindow.isNull()) { mainWindow = kisPart->createMainWindow(window.windowId); currentWindows.append(mainWindow); mainWindow->show(); } } } void closeUnneededWindows(QList> ¤tWindows) { QVector> windowsToClose; Q_FOREACH(KisMainWindow *mainWindow, currentWindows) { bool keep = false; Q_FOREACH(const Window &window, windows) { if (window.windowId == mainWindow->id()) { keep = true; break; } } if (!keep) { windowsToClose.append(mainWindow); // Set the window hidden to prevent "show image in all windows" feature from opening new views on it // while we migrate views onto the remaining windows mainWindow->hide(); } } migrateViewsFromClosingWindows(windowsToClose); Q_FOREACH(QPointer mainWindow, windowsToClose) { mainWindow->close(); } } void migrateViewsFromClosingWindows(QVector> &closingWindows) const { auto *kisPart = KisPart::instance(); KisMainWindow *migrationTarget = nullptr; Q_FOREACH(KisMainWindow *mainWindow, kisPart->mainWindows()) { if (!closingWindows.contains(mainWindow)) { migrationTarget = mainWindow; break; } } if (!migrationTarget) { qWarning() << "Problem: window layout with no windows would leave user with zero main windows."; migrationTarget = closingWindows.takeLast(); migrationTarget->show(); } QVector visibleDocuments; Q_FOREACH(KisView *view, kisPart->views()) { KisMainWindow *window = view->mainWindow(); if (!closingWindows.contains(window)) { visibleDocuments.append(view->document()); } } Q_FOREACH(KisDocument *document, kisPart->documents()) { if (!visibleDocuments.contains(document)) { visibleDocuments.append(document); migrationTarget->newView(document); } } } QList getScreensInConsistentOrder() { QList screens = QGuiApplication::screens(); std::sort(screens.begin(), screens.end(), [](const QScreen *a, const QScreen *b) { QRect aRect = a->geometry(); QRect bRect = b->geometry(); if (aRect.y() == bRect.y()) return aRect.x() < bRect.x(); return (aRect.y() < aRect.y()); }); return screens; } }; KisWindowLayoutResource::KisWindowLayoutResource(const QString &filename) : KoResource(filename) , d(new Private) {} KisWindowLayoutResource::~KisWindowLayoutResource() {} -KisWindowLayoutResource * KisWindowLayoutResource::fromCurrentWindows( +KisWindowLayoutResourceSP KisWindowLayoutResource::fromCurrentWindows( const QString &filename, const QList> &mainWindows, bool showImageInAllWindows, bool primaryWorkspaceFollowsFocus, KisMainWindow *primaryWindow ) { - auto resource = new KisWindowLayoutResource(filename); + KisWindowLayoutResourceSP resource(new KisWindowLayoutResource(filename)); resource->setWindows(mainWindows); resource->d->showImageInAllWindows = showImageInAllWindows; resource->d->primaryWorkspaceFollowsFocus = primaryWorkspaceFollowsFocus; resource->d->primaryWindow = primaryWindow->id(); return resource; } void KisWindowLayoutResource::applyLayout() { auto *kisPart = KisPart::instance(); auto *layoutManager= KisWindowLayoutManager::instance(); - layoutManager->setLastUsedLayout(this); + layoutManager->setLastUsedLayout(KisWindowLayoutResourceSP(this)); QList> currentWindows = kisPart->mainWindows(); if (d->windows.isEmpty()) { // No windows defined (e.g. fresh new session). Leave things as they are, but make sure there's at least one visible main window if (kisPart->mainwindowCount() == 0) { kisPart->createMainWindow(); } else { kisPart->mainWindows().first()->show(); } } else { d->openNecessaryWindows(currentWindows); d->closeUnneededWindows(currentWindows); } // Wait for the windows to finish opening / closing before applying saved geometry. // If we don't, the geometry may get reset after we apply it. QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); Q_FOREACH(const auto &window, d->windows) { QPointer mainWindow = kisPart->windowById(window.windowId); KIS_SAFE_ASSERT_RECOVER_BREAK(mainWindow); mainWindow->restoreGeometry(window.geometry); mainWindow->restoreWorkspaceState(window.windowState); } QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); QList screens = d->getScreensInConsistentOrder(); Q_FOREACH(const auto &window, d->windows) { if (window.screen >= 0 && window.screen < screens.size()) { QPointer mainWindow = kisPart->windowById(window.windowId); KIS_SAFE_ASSERT_RECOVER_BREAK(mainWindow); QWindow *windowHandle = mainWindow->windowHandle(); if (screens.indexOf(windowHandle->screen()) != window.screen) { QScreen *screen = screens[window.screen]; windowHandle->setScreen(screen); windowHandle->setPosition(screen->availableGeometry().topLeft()); } if (window.stateFlags) { mainWindow->setWindowState(window.stateFlags); } } } layoutManager->setShowImageInAllWindowsEnabled(d->showImageInAllWindows); layoutManager->setPrimaryWorkspaceFollowsFocus(d->primaryWorkspaceFollowsFocus, d->primaryWindow); } bool KisWindowLayoutResource::save() { if (filename().isEmpty()) return false; QFile file(filename()); file.open(QIODevice::WriteOnly); bool res = saveToDevice(&file); file.close(); return res; } bool KisWindowLayoutResource::load() { if (filename().isEmpty()) return false; QFile file(filename()); if (file.size() == 0) return false; if (!file.open(QIODevice::ReadOnly)) { warnKrita << "Can't open file " << filename(); return false; } bool res = loadFromDevice(&file); file.close(); return res; } bool KisWindowLayoutResource::saveToDevice(QIODevice *dev) const { QDomDocument doc; QDomElement root = doc.createElement("WindowLayout"); root.setAttribute("name", name()); root.setAttribute("version", WINDOW_LAYOUT_VERSION); saveXml(doc, root); doc.appendChild(root); QTextStream textStream(dev); textStream.setCodec("UTF-8"); doc.save(textStream, 4); KoResource::saveToDevice(dev); return true; } bool KisWindowLayoutResource::loadFromDevice(QIODevice *dev) { QDomDocument doc; if (!doc.setContent(dev)) { return false; } QDomElement element = doc.documentElement(); setName(element.attribute("name")); d->windows.clear(); loadXml(element); setValid(true); return true; } void KisWindowLayoutResource::saveXml(QDomDocument &doc, QDomElement &root) const { root.setAttribute("showImageInAllWindows", (int)d->showImageInAllWindows); root.setAttribute("primaryWorkspaceFollowsFocus", (int)d->primaryWorkspaceFollowsFocus); root.setAttribute("primaryWindow", d->primaryWindow.toString()); Q_FOREACH(const auto &window, d->windows) { QDomElement elem = doc.createElement("window"); elem.setAttribute("id", window.windowId.toString()); if (window.screen >= 0) { elem.setAttribute("screen", window.screen); } if (window.stateFlags & Qt::WindowMaximized) { elem.setAttribute("maximized", "1"); } QDomElement geometry = doc.createElement("geometry"); geometry.appendChild(doc.createCDATASection(window.geometry.toBase64())); elem.appendChild(geometry); QDomElement state = doc.createElement("windowState"); state.appendChild(doc.createCDATASection(window.windowState.toBase64())); elem.appendChild(state); root.appendChild(elem); } } void KisWindowLayoutResource::loadXml(const QDomElement &element) const { d->showImageInAllWindows = KisDomUtils::toInt(element.attribute("showImageInAllWindows", "0")); d->primaryWorkspaceFollowsFocus = KisDomUtils::toInt(element.attribute("primaryWorkspaceFollowsFocus", "0")); d->primaryWindow = element.attribute("primaryWindow"); for (auto windowElement = element.firstChildElement("window"); !windowElement.isNull(); windowElement = windowElement.nextSiblingElement("window")) { Private::Window window; window.windowId = QUuid(windowElement.attribute("id", QUuid().toString())); if (window.windowId.isNull()) { window.windowId = QUuid::createUuid(); } window.screen = windowElement.attribute("screen", "-1").toInt(); if (windowElement.attribute("maximized", "0") != "0") { window.stateFlags |= Qt::WindowMaximized; } QDomElement geometry = windowElement.firstChildElement("geometry"); QDomElement state = windowElement.firstChildElement("windowState"); window.geometry = QByteArray::fromBase64(geometry.text().toLatin1()); window.windowState = QByteArray::fromBase64(state.text().toLatin1()); d->windows.append(window); } } QString KisWindowLayoutResource::defaultFileExtension() const { return QString(".kwl"); } void KisWindowLayoutResource::setWindows(const QList> &mainWindows) { d->windows.clear(); QList screens = d->getScreensInConsistentOrder(); Q_FOREACH(auto window, mainWindows) { if (!window->isVisible()) continue; Private::Window state; state.windowId = window->id(); state.geometry = window->saveGeometry(); state.windowState = window->saveState(); state.stateFlags = window->windowState(); QWindow *windowHandle = window->windowHandle(); if (windowHandle) { int index = screens.indexOf(windowHandle->screen()); if (index >= 0) { state.screen = index; } } d->windows.append(state); } } diff --git a/libs/ui/KisWindowLayoutResource.h b/libs/ui/KisWindowLayoutResource.h index 7ca38ccc8e..ee61f73626 100644 --- a/libs/ui/KisWindowLayoutResource.h +++ b/libs/ui/KisWindowLayoutResource.h @@ -1,61 +1,65 @@ /* * Copyright (c) 2018 Jouni Pentikäinen * * 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 KISWINDOWLAYOUTRESOURCE_H #define KISWINDOWLAYOUTRESOURCE_H #include #include +class KisWindowLayoutResource; +typedef QSharedPointer KisWindowLayoutResourceSP; + class KisWindowLayoutResource : public KoResource { public: explicit KisWindowLayoutResource(const QString &filename); ~KisWindowLayoutResource() override; - static KisWindowLayoutResource * fromCurrentWindows( - const QString &filename, const QList> &mainWindows, - bool showImageInAllWindows, - bool primaryWorkspaceFollowsFocus, - KisMainWindow *primaryWindow - ); + static KisWindowLayoutResourceSP fromCurrentWindows ( + const QString &filename, const QList> &mainWindows, + bool showImageInAllWindows, + bool primaryWorkspaceFollowsFocus, + KisMainWindow *primaryWindow + ); void applyLayout(); bool save() override; bool load() override; bool saveToDevice(QIODevice *dev) const override; bool loadFromDevice(QIODevice *dev) override; QString defaultFileExtension() const override; protected: void setWindows(const QList> &mainWindows); virtual void saveXml(QDomDocument &doc, QDomElement &root) const; virtual void loadXml(const QDomElement &root) const; private: struct Private; QScopedPointer d; }; + #endif diff --git a/libs/ui/dialogs/KisDlgPaletteEditor.h b/libs/ui/dialogs/KisDlgPaletteEditor.h index dedd193f08..d668fcdb05 100644 --- a/libs/ui/dialogs/KisDlgPaletteEditor.h +++ b/libs/ui/dialogs/KisDlgPaletteEditor.h @@ -1,95 +1,95 @@ /* * Copyright (c) 2018 Michael Zhou * * 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 KISDLGPALETTEEDITOR_H #define KISDLGPALETTEEDITOR_H #include #include #include #include #include #include #include #include "kritaui_export.h" class QAction; class KoColorSet; class KisPaletteModel; class KisSwatchGroup; class KoDialog; class KisViewManager; class KisPaletteEditor; class Ui_WdgDlgPaletteEditor; /** * @brief The KisDlgPaletteEditor class * a dialog used by the palette docker to make modifications to a palette. * it automatically uploads all changes into the resource server when * the change is accepted */ class KRITAUI_EXPORT KisDlgPaletteEditor : public QDialog { Q_OBJECT public: explicit KisDlgPaletteEditor(); ~KisDlgPaletteEditor(); public: void setPaletteModel(KisPaletteModel *); - KoColorSet* palette() const { return m_colorSet; } + KoColorSetSP palette() const { return m_colorSet; } void setView(KisViewManager *); private Q_SLOTS: void slotDelGroup(); void slotAddGroup(); void slotRenGroup(); void slotGroupChosen(const QString &groupName); void slotRowCountChanged(int); void slotSetGlobal(); void slotNameChanged(); void slotFilenameChanged(const QString &newFilename); void slotFilenameInputFinished(); void slotColCountChanged(int); void slotAccepted(); private: QString oldNameFromNewName(const QString &newName) const; private: QScopedPointer m_ui; QScopedPointer m_actAddGroup; QScopedPointer m_actDelGroup; QScopedPointer m_actRenGroup; QScopedPointer m_globalButtons; QScopedPointer m_paletteEditor; - QPointer m_colorSet; + QSharedPointer m_colorSet; QString m_currentGroupOriginalName; QPalette m_normalPalette; QPalette m_warnPalette; }; #endif // KISKisDlgPaletteEditor_H diff --git a/libs/ui/dialogs/KisSessionManagerDialog.cpp b/libs/ui/dialogs/KisSessionManagerDialog.cpp index 6382254a2a..74698db05b 100644 --- a/libs/ui/dialogs/KisSessionManagerDialog.cpp +++ b/libs/ui/dialogs/KisSessionManagerDialog.cpp @@ -1,150 +1,150 @@ /* * Copyright (c) 2018 Jouni Pentikäinen * * 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 #include #include #include #include #include "KisSessionManagerDialog.h" KisSessionManagerDialog::KisSessionManagerDialog(QWidget *parent) : QDialog(parent) { setupUi(this); updateSessionList(); connect(btnNew, SIGNAL(clicked()), this, SLOT(slotNewSession())); connect(btnRename, SIGNAL(clicked()), this, SLOT(slotRenameSession())); connect(btnSwitchTo, SIGNAL(clicked()), this, SLOT(slotSwitchSession())); connect(btnDelete, SIGNAL(clicked()), this, SLOT(slotDeleteSession())); connect(btnClose, SIGNAL(clicked()), this, SLOT(slotClose())); connect(lstSessions, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(slotSessionDoubleClicked(QListWidgetItem*))); } void KisSessionManagerDialog::updateSessionList() { KoResourceServer *server = KisResourceServerProvider::instance()->sessionServer(); lstSessions->clear(); - Q_FOREACH(KisSessionResource *session, server->resources()) { + Q_FOREACH(KisSessionResourceSP session, server->resources()) { lstSessions->addItem(session->name()); } } void KisSessionManagerDialog::slotNewSession() { QString name = QInputDialog::getText(this, i18n("Create session"), i18n("Session name:"), QLineEdit::Normal ); if (name.isNull() || name.isEmpty()) return; - auto *session = new KisSessionResource(QString()); + KisSessionResourceSP session(new KisSessionResource(QString())); KoResourceServer *server = KisResourceServerProvider::instance()->sessionServer(); QString saveLocation = server->saveLocation(); QFileInfo fileInfo(saveLocation + name + session->defaultFileExtension()); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(saveLocation + name + QString("%1").arg(i) + session->defaultFileExtension()); i++; } session->setFilename(fileInfo.filePath()); session->setName(name); session->storeCurrentWindows(); server->addResource(session); KisPart::instance()->setCurrentSession(session); updateSessionList(); } void KisSessionManagerDialog::slotRenameSession() { QString name = QInputDialog::getText(this, i18n("Rename session"), i18n("New name:"), QLineEdit::Normal ); if (name.isNull() || name.isEmpty()) return; - KisSessionResource *session = getSelectedSession(); + KisSessionResourceSP session = getSelectedSession(); if (!session) return; session->setName(name); session->save(); updateSessionList(); } void KisSessionManagerDialog::slotSessionDoubleClicked(QListWidgetItem* /*item*/) { slotSwitchSession(); slotClose(); } void KisSessionManagerDialog::slotSwitchSession() { - KisSessionResource *session = getSelectedSession(); + KisSessionResourceSP session = getSelectedSession(); if (session) { bool closed = KisPart::instance()->closeSession(true); if (closed) { session->restore(); } } } -KisSessionResource *KisSessionManagerDialog::getSelectedSession() const +KisSessionResourceSP KisSessionManagerDialog::getSelectedSession() const { QListWidgetItem *item = lstSessions->currentItem(); if (item) { KoResourceServer *server = KisResourceServerProvider::instance()->sessionServer(); return server->resourceByName(item->text()); } return nullptr; } void KisSessionManagerDialog::slotDeleteSession() { - KisSessionResource *session = getSelectedSession(); + KisSessionResourceSP session = getSelectedSession(); if (!session) return; if (QMessageBox::warning(this, i18nc("@title:window", "Krita"), QString(i18n("Permanently delete session %1?", session->name())), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { const QString filename = session->filename(); KoResourceServer *server = KisResourceServerProvider::instance()->sessionServer(); server->removeResourceFromServer(session); QFile file(filename); file.remove(); updateSessionList(); } } void KisSessionManagerDialog::slotClose() { hide(); } diff --git a/libs/ui/dialogs/KisSessionManagerDialog.h b/libs/ui/dialogs/KisSessionManagerDialog.h index 5ba4566f92..48a0305c98 100644 --- a/libs/ui/dialogs/KisSessionManagerDialog.h +++ b/libs/ui/dialogs/KisSessionManagerDialog.h @@ -1,50 +1,50 @@ /* * Copyright (c) 2018 Jouni Pentikäinen * * 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 KISSESSIONMANAGERDIALOG_H #define KISSESSIONMANAGERDIALOG_H #include #include "ui_wdgsessionmanager.h" -class KisSessionResource; +#include class KisSessionManagerDialog : public QDialog, Ui::DlgSessionManager { Q_OBJECT public: explicit KisSessionManagerDialog(QWidget *parent = nullptr); private Q_SLOTS: void slotNewSession(); void slotRenameSession(); void slotSwitchSession(); void slotDeleteSession(); void slotSessionDoubleClicked(QListWidgetItem* item); void slotClose(); private: void updateSessionList(); - KisSessionResource *getSelectedSession() const; + KisSessionResourceSP getSelectedSession() const; }; #endif diff --git a/libs/ui/dialogs/kis_dlg_layer_style.cpp b/libs/ui/dialogs/kis_dlg_layer_style.cpp index ee36d22d3a..453ffc9a11 100644 --- a/libs/ui/dialogs/kis_dlg_layer_style.cpp +++ b/libs/ui/dialogs/kis_dlg_layer_style.cpp @@ -1,1452 +1,1447 @@ /* * Copyright (c) 2014 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_dlg_layer_style.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_config.h" #include "kis_cmb_contour.h" #include "kis_cmb_gradient.h" #include "KisResourceServerProvider.h" #include "kis_psd_layer_style_resource.h" #include "kis_psd_layer_style.h" #include "kis_signals_blocker.h" #include "kis_signal_compressor.h" #include "kis_canvas_resource_provider.h" #include -KoAbstractGradient* fetchGradientLazy(KoAbstractGradient *gradient, +KoAbstractGradientSP fetchGradientLazy(KoAbstractGradientSP gradient, KisCanvasResourceProvider *resourceProvider) { if (!gradient) { gradient = resourceProvider->currentGradient(); } return gradient; } KisDlgLayerStyle::KisDlgLayerStyle(KisPSDLayerStyleSP layerStyle, KisCanvasResourceProvider *resourceProvider, QWidget *parent) : KoDialog(parent) , m_layerStyle(layerStyle) , m_initialLayerStyle(layerStyle->clone()) , m_isSwitchingPredefinedStyle(false) , m_sanityLayerStyleDirty(false) { setCaption(i18n("Layer Styles")); setButtons(Ok | Cancel); setDefaultButton(Ok); m_configChangedCompressor = new KisSignalCompressor(1000, KisSignalCompressor::POSTPONE, this); connect(m_configChangedCompressor, SIGNAL(timeout()), SIGNAL(configChanged())); QWidget *page = new QWidget(this); wdgLayerStyles.setupUi(page); setMainWidget(page); wdgLayerStyles.chkPreview->setVisible(false); connect(wdgLayerStyles.lstStyleSelector, SIGNAL(itemChanged(QListWidgetItem*)), SLOT(notifyGuiConfigChanged())); m_stylesSelector = new StylesSelector(this); connect(m_stylesSelector, SIGNAL(styleSelected(KisPSDLayerStyleSP)), SLOT(notifyPredefinedStyleSelected(KisPSDLayerStyleSP))); wdgLayerStyles.stylesStack->addWidget(m_stylesSelector); m_blendingOptions = new BlendingOptions(this); wdgLayerStyles.stylesStack->addWidget(m_blendingOptions); m_dropShadow = new DropShadow(DropShadow::DropShadowMode, this); wdgLayerStyles.stylesStack->addWidget(m_dropShadow); connect(m_dropShadow, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); m_innerShadow = new DropShadow(DropShadow::InnerShadowMode, this); wdgLayerStyles.stylesStack->addWidget(m_innerShadow); connect(m_innerShadow, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); m_outerGlow = new InnerGlow(InnerGlow::OuterGlowMode, resourceProvider, this); wdgLayerStyles.stylesStack->addWidget(m_outerGlow); connect(m_outerGlow, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); m_innerGlow = new InnerGlow(InnerGlow::InnerGlowMode, resourceProvider, this); wdgLayerStyles.stylesStack->addWidget(m_innerGlow); connect(m_innerGlow, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); m_contour = new Contour(this); m_texture = new Texture(this); m_bevelAndEmboss = new BevelAndEmboss(m_contour, m_texture, this); wdgLayerStyles.stylesStack->addWidget(m_bevelAndEmboss); wdgLayerStyles.stylesStack->addWidget(m_contour); wdgLayerStyles.stylesStack->addWidget(m_texture); connect(m_bevelAndEmboss, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); m_satin = new Satin(this); wdgLayerStyles.stylesStack->addWidget(m_satin); connect(m_satin, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); m_colorOverlay = new ColorOverlay(this); wdgLayerStyles.stylesStack->addWidget(m_colorOverlay); connect(m_colorOverlay, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); m_gradientOverlay = new GradientOverlay(resourceProvider, this); wdgLayerStyles.stylesStack->addWidget(m_gradientOverlay); connect(m_gradientOverlay, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); m_patternOverlay = new PatternOverlay(this); wdgLayerStyles.stylesStack->addWidget(m_patternOverlay); connect(m_patternOverlay, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); m_stroke = new Stroke(resourceProvider, this); wdgLayerStyles.stylesStack->addWidget(m_stroke); connect(m_stroke, SIGNAL(configChanged()), SLOT(notifyGuiConfigChanged())); KisConfig cfg(true); wdgLayerStyles.stylesStack->setCurrentIndex(cfg.readEntry("KisDlgLayerStyle::current", 1)); wdgLayerStyles.lstStyleSelector->setCurrentRow(cfg.readEntry("KisDlgLayerStyle::current", 1)); connect(wdgLayerStyles.lstStyleSelector, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), this, SLOT(changePage(QListWidgetItem*,QListWidgetItem*))); notifyPredefinedStyleSelected(layerStyle); connect(m_dropShadow, SIGNAL(globalAngleChanged(int)), SLOT(syncGlobalAngle(int))); connect(m_innerShadow, SIGNAL(globalAngleChanged(int)), SLOT(syncGlobalAngle(int))); connect(m_bevelAndEmboss, SIGNAL(globalAngleChanged(int)), SLOT(syncGlobalAngle(int))); connect(wdgLayerStyles.btnNewStyle, SIGNAL(clicked()), SLOT(slotNewStyle())); connect(wdgLayerStyles.btnLoadStyle, SIGNAL(clicked()), SLOT(slotLoadStyle())); connect(wdgLayerStyles.btnSaveStyle, SIGNAL(clicked()), SLOT(slotSaveStyle())); connect(wdgLayerStyles.chkMasterFxSwitch, SIGNAL(toggled(bool)), SLOT(slotMasterFxSwitchChanged(bool))); connect(this, SIGNAL(accepted()), SLOT(slotNotifyOnAccept())); connect(this, SIGNAL(rejected()), SLOT(slotNotifyOnReject())); } KisDlgLayerStyle::~KisDlgLayerStyle() { } void KisDlgLayerStyle::slotMasterFxSwitchChanged(bool value) { wdgLayerStyles.lstStyleSelector->setEnabled(value); wdgLayerStyles.stylesStack->setEnabled(value); wdgLayerStyles.btnNewStyle->setEnabled(value); wdgLayerStyles.btnLoadStyle->setEnabled(value); wdgLayerStyles.btnSaveStyle->setEnabled(value); notifyGuiConfigChanged(); } void KisDlgLayerStyle::notifyGuiConfigChanged() { if (m_isSwitchingPredefinedStyle) return; m_configChangedCompressor->start(); m_layerStyle->setUuid(QUuid::createUuid()); m_sanityLayerStyleDirty = true; m_stylesSelector->notifyExternalStyleChanged(m_layerStyle->name(), m_layerStyle->uuid()); } void KisDlgLayerStyle::notifyPredefinedStyleSelected(KisPSDLayerStyleSP style) { m_isSwitchingPredefinedStyle = true; setStyle(style); m_isSwitchingPredefinedStyle = false; m_configChangedCompressor->start(); } void KisDlgLayerStyle::slotNotifyOnAccept() { if (m_configChangedCompressor->isActive()) { m_configChangedCompressor->stop(); emit configChanged(); } } void KisDlgLayerStyle::slotNotifyOnReject() { notifyPredefinedStyleSelected(m_initialLayerStyle); m_configChangedCompressor->stop(); emit configChanged(); } bool checkCustomNameAvailable(const QString &name) { const QString customName = "CustomStyles.asl"; KoResourceServer *server = KisResourceServerProvider::instance()->layerStyleCollectionServer(); - KoResource *resource = server->resourceByName(customName); + KoResourceSP resource = server->resourceByName(customName); if (!resource) return true; - KisPSDLayerStyleCollectionResource *collection = dynamic_cast(resource); + KisPSDLayerStyleCollectionResourceSP collection = resource.dynamicCast(); Q_FOREACH (KisPSDLayerStyleSP style, collection->layerStyles()) { if (style->name() == name) { return false; } } return true; } QString selectAvailableStyleName(const QString &name) { QString finalName = name; if (checkCustomNameAvailable(finalName)) { return finalName; } int i = 0; do { finalName = QString("%1%2").arg(name).arg(i++); } while (!checkCustomNameAvailable(finalName)); return finalName; } void KisDlgLayerStyle::slotNewStyle() { QString styleName = QInputDialog::getText(this, i18nc("@title:window", "Enter new style name"), i18nc("@label:textbox", "Name:"), QLineEdit::Normal, i18nc("Default name for a new style", "New Style")); KisPSDLayerStyleSP style = this->style(); style->setName(selectAvailableStyleName(styleName)); m_stylesSelector->addNewStyle(style->clone()); } void KisDlgLayerStyle::slotLoadStyle() { QString filename; // default value? KoFileDialog dialog(this, KoFileDialog::OpenFile, "layerstyle"); dialog.setCaption(i18n("Select ASL file")); dialog.setMimeTypeFilters(QStringList() << "application/x-photoshop-style-library", "application/x-photoshop-style-library"); filename = dialog.filename(); m_stylesSelector->loadCollection(filename); wdgLayerStyles.lstStyleSelector->setCurrentRow(0); } void KisDlgLayerStyle::slotSaveStyle() { QString filename; // default value? KoFileDialog dialog(this, KoFileDialog::SaveFile, "layerstyle"); dialog.setCaption(i18n("Select ASL file")); dialog.setMimeTypeFilters(QStringList() << "application/x-photoshop-style-library", "application/x-photoshop-style-library"); filename = dialog.filename(); QScopedPointer collection( new KisPSDLayerStyleCollectionResource(filename)); KisPSDLayerStyleSP newStyle = style()->clone(); newStyle->setName(QFileInfo(filename).baseName()); KisPSDLayerStyleCollectionResource::StylesVector vector = collection->layerStyles(); vector << newStyle; collection->setLayerStyles(vector); collection->save(); } void KisDlgLayerStyle::changePage(QListWidgetItem *current, QListWidgetItem *previous) { if (!current) { current = previous; } wdgLayerStyles.stylesStack->setCurrentIndex(wdgLayerStyles.lstStyleSelector->row(current)); } void KisDlgLayerStyle::setStyle(KisPSDLayerStyleSP style) { // we may self-assign style is some cases if (style != m_layerStyle) { *m_layerStyle = *style; } m_sanityLayerStyleDirty = false; { KisSignalsBlocker b(m_stylesSelector); m_stylesSelector->notifyExternalStyleChanged(m_layerStyle->name(), m_layerStyle->uuid()); } QListWidgetItem *item; item = wdgLayerStyles.lstStyleSelector->item(2); item->setCheckState(m_layerStyle->dropShadow()->effectEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(3); item->setCheckState(m_layerStyle->innerShadow()->effectEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(4); item->setCheckState(m_layerStyle->outerGlow()->effectEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(5); item->setCheckState(m_layerStyle->innerGlow()->effectEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(6); item->setCheckState(m_layerStyle->bevelAndEmboss()->effectEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(7); item->setCheckState(m_layerStyle->bevelAndEmboss()->contourEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(8); item->setCheckState(m_layerStyle->bevelAndEmboss()->textureEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(9); item->setCheckState(m_layerStyle->satin()->effectEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(10); item->setCheckState(m_layerStyle->colorOverlay()->effectEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(11); item->setCheckState(m_layerStyle->gradientOverlay()->effectEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(12); item->setCheckState(m_layerStyle->patternOverlay()->effectEnabled() ? Qt::Checked : Qt::Unchecked); item = wdgLayerStyles.lstStyleSelector->item(13); item->setCheckState(m_layerStyle->stroke()->effectEnabled() ? Qt::Checked : Qt::Unchecked); m_dropShadow->setShadow(m_layerStyle->dropShadow()); m_innerShadow->setShadow(m_layerStyle->innerShadow()); m_outerGlow->setConfig(m_layerStyle->outerGlow()); m_innerGlow->setConfig(m_layerStyle->innerGlow()); m_bevelAndEmboss->setBevelAndEmboss(m_layerStyle->bevelAndEmboss()); m_satin->setSatin(m_layerStyle->satin()); m_colorOverlay->setColorOverlay(m_layerStyle->colorOverlay()); m_gradientOverlay->setGradientOverlay(m_layerStyle->gradientOverlay()); m_patternOverlay->setPatternOverlay(m_layerStyle->patternOverlay()); m_stroke->setStroke(m_layerStyle->stroke()); wdgLayerStyles.chkMasterFxSwitch->setChecked(m_layerStyle->isEnabled()); slotMasterFxSwitchChanged(m_layerStyle->isEnabled()); } KisPSDLayerStyleSP KisDlgLayerStyle::style() const { m_layerStyle->setEnabled(wdgLayerStyles.chkMasterFxSwitch->isChecked()); m_layerStyle->dropShadow()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(2)->checkState() == Qt::Checked); m_layerStyle->innerShadow()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(3)->checkState() == Qt::Checked); m_layerStyle->outerGlow()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(4)->checkState() == Qt::Checked); m_layerStyle->innerGlow()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(5)->checkState() == Qt::Checked); m_layerStyle->bevelAndEmboss()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(6)->checkState() == Qt::Checked); m_layerStyle->bevelAndEmboss()->setContourEnabled(wdgLayerStyles.lstStyleSelector->item(7)->checkState() == Qt::Checked); m_layerStyle->bevelAndEmboss()->setTextureEnabled(wdgLayerStyles.lstStyleSelector->item(8)->checkState() == Qt::Checked); m_layerStyle->satin()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(9)->checkState() == Qt::Checked); m_layerStyle->colorOverlay()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(10)->checkState() == Qt::Checked); m_layerStyle->gradientOverlay()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(11)->checkState() == Qt::Checked); m_layerStyle->patternOverlay()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(12)->checkState() == Qt::Checked); m_layerStyle->stroke()->setEffectEnabled(wdgLayerStyles.lstStyleSelector->item(13)->checkState() == Qt::Checked); m_dropShadow->fetchShadow(m_layerStyle->dropShadow()); m_innerShadow->fetchShadow(m_layerStyle->innerShadow()); m_outerGlow->fetchConfig(m_layerStyle->outerGlow()); m_innerGlow->fetchConfig(m_layerStyle->innerGlow()); m_bevelAndEmboss->fetchBevelAndEmboss(m_layerStyle->bevelAndEmboss()); m_satin->fetchSatin(m_layerStyle->satin()); m_colorOverlay->fetchColorOverlay(m_layerStyle->colorOverlay()); m_gradientOverlay->fetchGradientOverlay(m_layerStyle->gradientOverlay()); m_patternOverlay->fetchPatternOverlay(m_layerStyle->patternOverlay()); m_stroke->fetchStroke(m_layerStyle->stroke()); m_sanityLayerStyleDirty = false; m_stylesSelector->notifyExternalStyleChanged(m_layerStyle->name(), m_layerStyle->uuid()); return m_layerStyle; } void KisDlgLayerStyle::syncGlobalAngle(int angle) { KisPSDLayerStyleSP style = this->style(); if (style->dropShadow()->useGlobalLight()) { style->dropShadow()->setAngle(angle); } if (style->innerShadow()->useGlobalLight()) { style->innerShadow()->setAngle(angle); } if (style->bevelAndEmboss()->useGlobalLight()) { style->bevelAndEmboss()->setAngle(angle); } setStyle(style); } /********************************************************************/ /***** Styles Selector **********************************************/ /********************************************************************/ class StyleItem : public QListWidgetItem { public: StyleItem(KisPSDLayerStyleSP style) : QListWidgetItem(style->name()) , m_style(style) { } public: KisPSDLayerStyleSP m_style; }; StylesSelector::StylesSelector(QWidget *parent) : QWidget(parent) { ui.setupUi(this); connect(ui.cmbStyleCollections, SIGNAL(activated(QString)), this, SLOT(loadStyles(QString))); connect(ui.listStyles, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), this, SLOT(selectStyle(QListWidgetItem*,QListWidgetItem*))); refillCollections(); if (ui.cmbStyleCollections->count()) { ui.cmbStyleCollections->setCurrentIndex(0); loadStyles(ui.cmbStyleCollections->currentText()); } } void StylesSelector::refillCollections() { QString previousCollection = ui.cmbStyleCollections->currentText(); ui.cmbStyleCollections->clear(); - Q_FOREACH (KoResource *res, KisResourceServerProvider::instance()->layerStyleCollectionServer()->resources()) { + Q_FOREACH (KoResourceSP res, KisResourceServerProvider::instance()->layerStyleCollectionServer()->resources()) { ui.cmbStyleCollections->addItem(res->name()); } if (!previousCollection.isEmpty()) { KisSignalsBlocker blocker(this); int index = ui.cmbStyleCollections->findText(previousCollection); ui.cmbStyleCollections->setCurrentIndex(index); } } void StylesSelector::notifyExternalStyleChanged(const QString &name, const QUuid &uuid) { int currentIndex = -1; for (int i = 0; i < ui.listStyles->count(); i++ ) { StyleItem *item = dynamic_cast(ui.listStyles->item(i)); QString itemName = item->m_style->name(); if (itemName == name) { bool isDirty = item->m_style->uuid() != uuid; if (isDirty) { itemName += "*"; } currentIndex = i; } item->setText(itemName); } ui.listStyles->setCurrentRow(currentIndex); } void StylesSelector::loadStyles(const QString &name) { ui.listStyles->clear(); - KoResource *res = KisResourceServerProvider::instance()->layerStyleCollectionServer()->resourceByName(name); - KisPSDLayerStyleCollectionResource *collection = dynamic_cast(res); + KoResourceSP res = KisResourceServerProvider::instance()->layerStyleCollectionServer()->resourceByName(name); + KisPSDLayerStyleCollectionResourceSP collection = res.dynamicCast(); if (collection) { Q_FOREACH (KisPSDLayerStyleSP style, collection->layerStyles()) { // XXX: also use the preview image, when we have one ui.listStyles->addItem(new StyleItem(style)); } } } void StylesSelector::selectStyle(QListWidgetItem *current, QListWidgetItem* /*previous*/) { StyleItem *item = dynamic_cast(current); if (item) { emit styleSelected(item->m_style); } } void StylesSelector::loadCollection(const QString &fileName) { if (!QFileInfo(fileName).exists()) { warnKrita << "Loaded style collection doesn't exist!"; return; } - KisPSDLayerStyleCollectionResource *collection = - new KisPSDLayerStyleCollectionResource(fileName); + KisPSDLayerStyleCollectionResourceSP collection = KisPSDLayerStyleCollectionResourceSP(new KisPSDLayerStyleCollectionResource(fileName)); collection->load(); KoResourceServer *server = KisResourceServerProvider::instance()->layerStyleCollectionServer(); collection->setFilename(server->saveLocation() + QDir::separator() + collection->name()); server->addResource(collection); refillCollections(); int index = ui.cmbStyleCollections->findText(collection->name()); ui.cmbStyleCollections->setCurrentIndex(index); loadStyles(collection->name()); } void StylesSelector::addNewStyle(KisPSDLayerStyleSP style) { KoResourceServer *server = KisResourceServerProvider::instance()->layerStyleCollectionServer(); // NOTE: not translatable, since it is a key! const QString customName = "CustomStyles.asl"; const QString saveLocation = server->saveLocation(); const QString fullFilename = saveLocation + customName; - KoResource *resource = server->resourceByName(customName); - KisPSDLayerStyleCollectionResource *collection = 0; + KoResourceSP resource = server->resourceByName(customName); + KisPSDLayerStyleCollectionResourceSP collection; if (!resource) { - collection = new KisPSDLayerStyleCollectionResource(""); + collection = KisPSDLayerStyleCollectionResourceSP(new KisPSDLayerStyleCollectionResource("")); collection->setName(customName); collection->setFilename(fullFilename); KisPSDLayerStyleCollectionResource::StylesVector vector; vector << style; collection->setLayerStyles(vector); server->addResource(collection); - } else { - collection = dynamic_cast(resource); + } + else { + collection = resource.dynamicCast(); KisPSDLayerStyleCollectionResource::StylesVector vector; vector = collection->layerStyles(); vector << style; collection->setLayerStyles(vector); collection->save(); } refillCollections(); // select in gui int index = ui.cmbStyleCollections->findText(customName); KIS_ASSERT_RECOVER_RETURN(index >= 0); ui.cmbStyleCollections->setCurrentIndex(index); loadStyles(customName); notifyExternalStyleChanged(style->name(), style->uuid()); } /********************************************************************/ /***** Bevel and Emboss *********************************************/ /********************************************************************/ BevelAndEmboss::BevelAndEmboss(Contour *contour, Texture *texture, QWidget *parent) : QWidget(parent) , m_contour(contour) , m_texture(texture) { ui.setupUi(this); // Structure ui.intDepth->setRange(0, 100); ui.intDepth->setSuffix(i18n(" %")); ui.intSize->setRange(0, 250); ui.intSize->setSuffix(i18n(" px")); ui.intSoften->setRange(0, 18); ui.intSoften->setSuffix(i18n(" px")); connect(ui.cmbStyle, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.cmbTechnique, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.intDepth, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.cmbDirection, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.intSize, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intSoften, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); // Shading ui.intOpacity->setRange(0, 100); ui.intOpacity->setSuffix(i18n(" %")); ui.intOpacity2->setRange(0, 100); ui.intOpacity2->setSuffix(i18n(" %")); connect(ui.dialAngle, SIGNAL(valueChanged(int)), SLOT(slotDialAngleChanged(int))); connect(ui.intAngle, SIGNAL(valueChanged(int)), SLOT(slotIntAngleChanged(int))); connect(ui.chkUseGlobalLight, SIGNAL(toggled(bool)), SLOT(slotGlobalLightToggled())); connect(ui.dialAngle, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intAngle, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.chkUseGlobalLight, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.intAltitude, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.cmbContour, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.chkAntiAliased, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.cmbHighlightMode, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.bnHighlightColor, SIGNAL(changed(KoColor)), SIGNAL(configChanged())); connect(ui.intOpacity, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.cmbShadowMode, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.bnShadowColor, SIGNAL(changed(KoColor)), SIGNAL(configChanged())); connect(ui.intOpacity2, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); // Contour m_contour->ui.intRange->setRange(1, 100); m_contour->ui.intRange->setSuffix(i18n(" %")); connect(m_contour->ui.cmbContour, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(m_contour->ui.chkAntiAliased, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(m_contour->ui.intRange, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); // Texture m_texture->ui.intScale->setRange(0, 100); m_texture->ui.intScale->setSuffix(i18n(" %")); m_texture->ui.intDepth->setRange(-1000, 1000); m_texture->ui.intDepth->setSuffix(i18n(" %")); - connect(m_texture->ui.patternChooser, SIGNAL(resourceSelected(KoResource*)), SIGNAL(configChanged())); + connect(m_texture->ui.patternChooser, SIGNAL(resourceSelected(KoResourceSP )), SIGNAL(configChanged())); connect(m_texture->ui.intScale, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(m_texture->ui.intDepth, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(m_texture->ui.chkInvert, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(m_texture->ui.chkLinkWithLayer, SIGNAL(toggled(bool)), SIGNAL(configChanged())); } void BevelAndEmboss::setBevelAndEmboss(const psd_layer_effects_bevel_emboss *bevelAndEmboss) { ui.cmbStyle->setCurrentIndex((int)bevelAndEmboss->style()); ui.cmbTechnique->setCurrentIndex((int)bevelAndEmboss->technique()); ui.intDepth->setValue(bevelAndEmboss->depth()); ui.cmbDirection->setCurrentIndex((int)bevelAndEmboss->direction()); ui.intSize->setValue(bevelAndEmboss->size()); ui.intSoften->setValue(bevelAndEmboss->soften()); ui.dialAngle->setValue(bevelAndEmboss->angle()); ui.intAngle->setValue(bevelAndEmboss->angle()); ui.chkUseGlobalLight->setChecked(bevelAndEmboss->useGlobalLight()); ui.intAltitude->setValue(bevelAndEmboss->altitude()); // FIXME: curve editing // ui.cmbContour; ui.chkAntiAliased->setChecked(bevelAndEmboss->glossAntiAliased()); ui.cmbHighlightMode->selectCompositeOp(KoID(bevelAndEmboss->highlightBlendMode())); KoColor highlightshadow(KoColorSpaceRegistry::instance()->rgb8()); highlightshadow.fromQColor(bevelAndEmboss->highlightColor()); ui.bnHighlightColor->setColor(highlightshadow); ui.intOpacity->setValue(bevelAndEmboss->highlightOpacity()); ui.cmbShadowMode->selectCompositeOp(KoID(bevelAndEmboss->shadowBlendMode())); highlightshadow.fromQColor(bevelAndEmboss->shadowColor()); ui.bnShadowColor->setColor(highlightshadow); ui.intOpacity2->setValue(bevelAndEmboss->shadowOpacity()); // FIXME: curve editing // m_contour->ui.cmbContour; m_contour->ui.chkAntiAliased->setChecked(bevelAndEmboss->antiAliased()); m_contour->ui.intRange->setValue(bevelAndEmboss->contourRange()); m_texture->ui.patternChooser->setCurrentPattern(bevelAndEmboss->texturePattern()); m_texture->ui.intScale->setValue(bevelAndEmboss->textureScale()); m_texture->ui.intDepth->setValue(bevelAndEmboss->textureDepth()); m_texture->ui.chkInvert->setChecked(bevelAndEmboss->textureInvert()); m_texture->ui.chkLinkWithLayer->setChecked(bevelAndEmboss->textureAlignWithLayer()); } void BevelAndEmboss::fetchBevelAndEmboss(psd_layer_effects_bevel_emboss *bevelAndEmboss) const { bevelAndEmboss->setStyle((psd_bevel_style)ui.cmbStyle->currentIndex()); bevelAndEmboss->setTechnique((psd_technique_type)ui.cmbTechnique->currentIndex()); bevelAndEmboss->setDepth(ui.intDepth->value()); bevelAndEmboss->setDirection((psd_direction)ui.cmbDirection->currentIndex()); bevelAndEmboss->setSize(ui.intSize->value()); bevelAndEmboss->setSoften(ui.intSoften->value()); bevelAndEmboss->setAngle(ui.dialAngle->value()); bevelAndEmboss->setUseGlobalLight(ui.chkUseGlobalLight->isChecked()); bevelAndEmboss->setAltitude(ui.intAltitude->value()); bevelAndEmboss->setGlossAntiAliased(ui.chkAntiAliased->isChecked()); bevelAndEmboss->setHighlightBlendMode(ui.cmbHighlightMode->selectedCompositeOp().id()); bevelAndEmboss->setHighlightColor(ui.bnHighlightColor->color().toQColor()); bevelAndEmboss->setHighlightOpacity(ui.intOpacity->value()); bevelAndEmboss->setShadowBlendMode(ui.cmbShadowMode->selectedCompositeOp().id()); bevelAndEmboss->setShadowColor(ui.bnShadowColor->color().toQColor()); bevelAndEmboss->setShadowOpacity(ui.intOpacity2->value()); // FIXME: curve editing bevelAndEmboss->setAntiAliased(m_contour->ui.chkAntiAliased->isChecked()); bevelAndEmboss->setContourRange(m_contour->ui.intRange->value()); - bevelAndEmboss->setTexturePattern(static_cast(m_texture->ui.patternChooser->currentResource())); + bevelAndEmboss->setTexturePattern(m_texture->ui.patternChooser->currentResource().staticCast()); bevelAndEmboss->setTextureScale(m_texture->ui.intScale->value()); bevelAndEmboss->setTextureDepth(m_texture->ui.intDepth->value()); bevelAndEmboss->setTextureInvert(m_texture->ui.chkInvert->isChecked()); bevelAndEmboss->setTextureAlignWithLayer(m_texture->ui.chkLinkWithLayer->isChecked()); } void BevelAndEmboss::slotDialAngleChanged(int value) { KisSignalsBlocker b(ui.intAngle); ui.intAngle->setValue(value); if (ui.chkUseGlobalLight->isChecked()) { emit globalAngleChanged(value); } } void BevelAndEmboss::slotIntAngleChanged(int value) { KisSignalsBlocker b(ui.dialAngle); ui.dialAngle->setValue(value); if (ui.chkUseGlobalLight->isChecked()) { emit globalAngleChanged(value); } } void BevelAndEmboss::slotGlobalLightToggled() { if (ui.chkUseGlobalLight->isChecked()) { emit globalAngleChanged(ui.intAngle->value()); } } /********************************************************************/ /***** Texture *********************************************/ /********************************************************************/ Texture::Texture(QWidget *parent) : QWidget(parent) { ui.setupUi(this); } /********************************************************************/ /***** Contour *********************************************/ /********************************************************************/ Contour::Contour(QWidget *parent) : QWidget(parent) { ui.setupUi(this); } /********************************************************************/ /***** Blending Options *********************************************/ /********************************************************************/ BlendingOptions::BlendingOptions(QWidget *parent) : QWidget(parent) { ui.setupUi(this); // FIXME: Blend options are not implemented yet ui.grpBlendingOptions->setTitle(QString("%1 (%2)").arg(ui.grpBlendingOptions->title()).arg(i18n("Not Implemented Yet"))); ui.grpBlendingOptions->setEnabled(false); } /********************************************************************/ /***** Color Overlay *********************************************/ /********************************************************************/ ColorOverlay::ColorOverlay(QWidget *parent) : QWidget(parent) { ui.setupUi(this); ui.intOpacity->setRange(0, 100); ui.intOpacity->setSuffix(i18n(" %")); connect(ui.cmbCompositeOp, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.intOpacity, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.bnColor, SIGNAL(changed(KoColor)), SIGNAL(configChanged())); } void ColorOverlay::setColorOverlay(const psd_layer_effects_color_overlay *colorOverlay) { ui.cmbCompositeOp->selectCompositeOp(KoID(colorOverlay->blendMode())); ui.intOpacity->setValue(colorOverlay->opacity()); KoColor color(KoColorSpaceRegistry::instance()->rgb8()); color.fromQColor(colorOverlay->color()); ui.bnColor->setColor(color); } void ColorOverlay::fetchColorOverlay(psd_layer_effects_color_overlay *colorOverlay) const { colorOverlay->setBlendMode(ui.cmbCompositeOp->selectedCompositeOp().id()); colorOverlay->setOpacity(ui.intOpacity->value()); colorOverlay->setColor(ui.bnColor->color().toQColor()); } /********************************************************************/ /***** Drop Shadow **************************************************/ /********************************************************************/ DropShadow::DropShadow(Mode mode, QWidget *parent) : QWidget(parent), m_mode(mode) { ui.setupUi(this); ui.intOpacity->setRange(0, 100); ui.intOpacity->setSuffix(i18n(" %")); ui.intDistance->setRange(0, 500); ui.intDistance->setSuffix(i18n(" px")); ui.intDistance->setExponentRatio(3.0); ui.intSpread->setRange(0, 100); ui.intSpread->setSuffix(i18n(" %")); ui.intSize->setRange(0, 250); ui.intSize->setSuffix(i18n(" px")); ui.intNoise->setRange(0, 100); ui.intNoise->setSuffix(i18n(" %")); connect(ui.dialAngle, SIGNAL(valueChanged(int)), SLOT(slotDialAngleChanged(int))); connect(ui.intAngle, SIGNAL(valueChanged(int)), SLOT(slotIntAngleChanged(int))); connect(ui.chkUseGlobalLight, SIGNAL(toggled(bool)), SLOT(slotGlobalLightToggled())); // connect everything to configChanged() signal connect(ui.cmbCompositeOp, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.intOpacity, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.bnColor, SIGNAL(changed(KoColor)), SIGNAL(configChanged())); connect(ui.dialAngle, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intAngle, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.chkUseGlobalLight, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.intDistance, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intSpread, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intSize, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.cmbContour, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.chkAntiAliased, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.intNoise, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.chkLayerKnocksOutDropShadow, SIGNAL(toggled(bool)), SIGNAL(configChanged())); if (m_mode == InnerShadowMode) { ui.chkLayerKnocksOutDropShadow->setVisible(false); ui.grpMain->setTitle(i18n("Inner Shadow")); ui.lblSpread->setText(i18n("Choke:")); } } void DropShadow::slotDialAngleChanged(int value) { KisSignalsBlocker b(ui.intAngle); ui.intAngle->setValue(value); if (ui.chkUseGlobalLight->isChecked()) { emit globalAngleChanged(value); } } void DropShadow::slotIntAngleChanged(int value) { KisSignalsBlocker b(ui.dialAngle); ui.dialAngle->setValue(value); if (ui.chkUseGlobalLight->isChecked()) { emit globalAngleChanged(value); } } void DropShadow::slotGlobalLightToggled() { if (ui.chkUseGlobalLight->isChecked()) { emit globalAngleChanged(ui.intAngle->value()); } } void DropShadow::setShadow(const psd_layer_effects_shadow_common *shadow) { ui.cmbCompositeOp->selectCompositeOp(KoID(shadow->blendMode())); ui.intOpacity->setValue(shadow->opacity()); KoColor color(KoColorSpaceRegistry::instance()->rgb8()); color.fromQColor(shadow->color()); ui.bnColor->setColor(color); ui.dialAngle->setValue(shadow->angle()); ui.intAngle->setValue(shadow->angle()); ui.chkUseGlobalLight->setChecked(shadow->useGlobalLight()); ui.intDistance->setValue(shadow->distance()); ui.intSpread->setValue(shadow->spread()); ui.intSize->setValue(shadow->size()); // FIXME: curve editing // ui.cmbContour; ui.chkAntiAliased->setChecked(shadow->antiAliased()); ui.intNoise->setValue(shadow->noise()); if (m_mode == DropShadowMode) { const psd_layer_effects_drop_shadow *realDropShadow = dynamic_cast(shadow); KIS_ASSERT_RECOVER_NOOP(realDropShadow); ui.chkLayerKnocksOutDropShadow->setChecked(shadow->knocksOut()); } } void DropShadow::fetchShadow(psd_layer_effects_shadow_common *shadow) const { shadow->setBlendMode(ui.cmbCompositeOp->selectedCompositeOp().id()); shadow->setOpacity(ui.intOpacity->value()); shadow->setColor(ui.bnColor->color().toQColor()); shadow->setAngle(ui.dialAngle->value()); shadow->setUseGlobalLight(ui.chkUseGlobalLight->isChecked()); shadow->setDistance(ui.intDistance->value()); shadow->setSpread(ui.intSpread->value()); shadow->setSize(ui.intSize->value()); // FIXME: curve editing // ui.cmbContour; shadow->setAntiAliased(ui.chkAntiAliased->isChecked()); shadow->setNoise(ui.intNoise->value()); if (m_mode == DropShadowMode) { psd_layer_effects_drop_shadow *realDropShadow = dynamic_cast(shadow); KIS_ASSERT_RECOVER_NOOP(realDropShadow); realDropShadow->setKnocksOut(ui.chkLayerKnocksOutDropShadow->isChecked()); } } class GradientPointerConverter { public: - static KoAbstractGradientSP resourceToStyle(KoAbstractGradient *gradient) { + static KoAbstractGradientSP resourceToStyle(KoAbstractGradientSP gradient) { return gradient ? KoAbstractGradientSP(gradient->clone()) : KoAbstractGradientSP(); } - static KoAbstractGradient* styleToResource(KoAbstractGradientSP gradient) { + static KoAbstractGradientSP styleToResource(KoAbstractGradientSP gradient) { if (!gradient) return 0; KoResourceServer *server = KoResourceServerProvider::instance()->gradientServer(); - KoAbstractGradient *resource = server->resourceByMD5(gradient->md5()); + KoAbstractGradientSP resource = server->resourceByMD5(gradient->md5()); if (!resource) { - KoAbstractGradient *clone = gradient->clone(); + KoAbstractGradientSP clone = gradient->clone(); clone->setName(findAvailableName(gradient->name())); server->addResource(clone, false); resource = clone; } return resource; } private: static QString findAvailableName(const QString &name) { KoResourceServer *server = KoResourceServerProvider::instance()->gradientServer(); QString newName = name; int i = 0; while (server->resourceByName(newName)) { newName = QString("%1%2").arg(name).arg(i++); } return newName; } }; /********************************************************************/ /***** Gradient Overlay *********************************************/ /********************************************************************/ GradientOverlay::GradientOverlay(KisCanvasResourceProvider *resourceProvider, QWidget *parent) : QWidget(parent), m_resourceProvider(resourceProvider) { ui.setupUi(this); ui.intOpacity->setRange(0, 100); ui.intOpacity->setSuffix(i18n(" %")); ui.intScale->setRange(0, 100); ui.intScale->setSuffix(i18n(" %")); connect(ui.dialAngle, SIGNAL(valueChanged(int)), SLOT(slotDialAngleChanged(int))); connect(ui.intAngle, SIGNAL(valueChanged(int)), SLOT(slotIntAngleChanged(int))); connect(ui.cmbCompositeOp, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.intOpacity, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.cmbGradient, SIGNAL(gradientChanged(KoAbstractGradient*)), SIGNAL(configChanged())); connect(ui.chkReverse, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.cmbStyle, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.chkAlignWithLayer, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.dialAngle, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intAngle, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intScale, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); } void GradientOverlay::setGradientOverlay(const psd_layer_effects_gradient_overlay *config) { ui.cmbCompositeOp->selectCompositeOp(KoID(config->blendMode())); ui.intOpacity->setValue(config->opacity()); - KoAbstractGradient *gradient = fetchGradientLazy( - GradientPointerConverter::styleToResource(config->gradient()), m_resourceProvider); + KoAbstractGradientSP gradient = fetchGradientLazy(GradientPointerConverter::styleToResource(config->gradient()), m_resourceProvider); if (gradient) { ui.cmbGradient->setGradient(gradient); } ui.chkReverse->setChecked(config->reverse()); ui.cmbStyle->setCurrentIndex((int)config->style()); ui.chkAlignWithLayer->setCheckable(config->alignWithLayer()); ui.dialAngle->setValue(config->angle()); ui.intAngle->setValue(config->angle()); ui.intScale->setValue(config->scale()); } void GradientOverlay::fetchGradientOverlay(psd_layer_effects_gradient_overlay *config) const { config->setBlendMode(ui.cmbCompositeOp->selectedCompositeOp().id()); config->setOpacity(ui.intOpacity->value()); config->setGradient(GradientPointerConverter::resourceToStyle(ui.cmbGradient->gradient())); config->setReverse(ui.chkReverse->isChecked()); config->setStyle((psd_gradient_style)ui.cmbStyle->currentIndex()); config->setAlignWithLayer(ui.chkAlignWithLayer->isChecked()); config->setAngle(ui.dialAngle->value()); config->setScale(ui.intScale->value()); } void GradientOverlay::slotDialAngleChanged(int value) { KisSignalsBlocker b(ui.intAngle); ui.intAngle->setValue(value); } void GradientOverlay::slotIntAngleChanged(int value) { KisSignalsBlocker b(ui.dialAngle); ui.dialAngle->setValue(value); } /********************************************************************/ /***** Innner Glow *********************************************/ /********************************************************************/ InnerGlow::InnerGlow(Mode mode, KisCanvasResourceProvider *resourceProvider, QWidget *parent) : QWidget(parent), m_mode(mode), m_resourceProvider(resourceProvider) { ui.setupUi(this); ui.intOpacity->setRange(0, 100); ui.intOpacity->setSuffix(i18n(" %")); ui.intNoise->setRange(0, 100); ui.intNoise->setSuffix(i18n(" %")); ui.intChoke->setRange(0, 100); ui.intChoke->setSuffix(i18n(" %")); ui.intSize->setRange(0, 250); ui.intSize->setSuffix(i18n(" px")); ui.intRange->setRange(1, 100); ui.intRange->setSuffix(i18n(" %")); ui.intJitter->setRange(0, 100); ui.intJitter->setSuffix(i18n(" %")); connect(ui.cmbCompositeOp, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.intOpacity, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intNoise, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.radioColor, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.bnColor, SIGNAL(changed(KoColor)), SIGNAL(configChanged())); connect(ui.radioGradient, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.cmbGradient, SIGNAL(gradientChanged(KoAbstractGradient*)), SIGNAL(configChanged())); connect(ui.cmbTechnique, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.cmbSource, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.intChoke, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intSize, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.cmbContour, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.chkAntiAliased, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.intRange, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intJitter, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); if (m_mode == OuterGlowMode) { ui.cmbSource->hide(); ui.lblSource->hide(); ui.lblChoke->setText(i18nc("layer styles parameter", "Spread:")); } } void InnerGlow::setConfig(const psd_layer_effects_glow_common *config) { ui.cmbCompositeOp->selectCompositeOp(KoID(config->blendMode())); ui.intOpacity->setValue(config->opacity()); ui.intNoise->setValue(config->noise()); ui.radioColor->setChecked(config->fillType() == psd_fill_solid_color); KoColor color(KoColorSpaceRegistry::instance()->rgb8()); color.fromQColor(config->color()); ui.bnColor->setColor(color); ui.radioGradient->setChecked(config->fillType() == psd_fill_gradient); - KoAbstractGradient *gradient = fetchGradientLazy( - GradientPointerConverter::styleToResource(config->gradient()), m_resourceProvider); + KoAbstractGradientSP gradient = fetchGradientLazy(GradientPointerConverter::styleToResource(config->gradient()), m_resourceProvider); if (gradient) { ui.cmbGradient->setGradient(gradient); } ui.cmbTechnique->setCurrentIndex((int)config->technique()); ui.intChoke->setValue(config->spread()); ui.intSize->setValue(config->size()); if (m_mode == InnerGlowMode) { const psd_layer_effects_inner_glow *iglow = dynamic_cast(config); KIS_ASSERT_RECOVER_RETURN(iglow); ui.cmbSource->setCurrentIndex(iglow->source() == psd_glow_edge); } // FIXME: Curve editing //ui.cmbContour; ui.chkAntiAliased->setChecked(config->antiAliased()); ui.intRange->setValue(config->range()); ui.intJitter->setValue(config->jitter()); } void InnerGlow::fetchConfig(psd_layer_effects_glow_common *config) const { config->setBlendMode(ui.cmbCompositeOp->selectedCompositeOp().id()); config->setOpacity(ui.intOpacity->value()); config->setNoise(ui.intNoise->value()); if (ui.radioColor->isChecked()) { config->setFillType(psd_fill_solid_color); } else { config->setFillType(psd_fill_gradient); } config->setColor(ui.bnColor->color().toQColor()); config->setGradient(GradientPointerConverter::resourceToStyle(ui.cmbGradient->gradient())); config->setTechnique((psd_technique_type)ui.cmbTechnique->currentIndex()); config->setSpread(ui.intChoke->value()); config->setSize(ui.intSize->value()); if (m_mode == InnerGlowMode) { psd_layer_effects_inner_glow *iglow = dynamic_cast(config); KIS_ASSERT_RECOVER_RETURN(iglow); iglow->setSource((psd_glow_source)ui.cmbSource->currentIndex()); } // FIXME: Curve editing //ui.cmbContour; config->setAntiAliased(ui.chkAntiAliased->isChecked()); config->setRange(ui.intRange->value()); config->setJitter(ui.intJitter->value()); } /********************************************************************/ /***** Pattern Overlay *********************************************/ /********************************************************************/ PatternOverlay::PatternOverlay(QWidget *parent) : QWidget(parent) { ui.setupUi(this); ui.intOpacity->setRange(0, 100); ui.intOpacity->setSuffix(i18n(" %")); ui.intScale->setRange(0, 100); ui.intScale->setSuffix(i18n(" %")); connect(ui.cmbCompositeOp, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.intOpacity, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); - connect(ui.patternChooser, SIGNAL(resourceSelected(KoResource*)), SIGNAL(configChanged())); + connect(ui.patternChooser, SIGNAL(resourceSelected(KoResourceSP )), SIGNAL(configChanged())); connect(ui.chkLinkWithLayer, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.intScale, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); } void PatternOverlay::setPatternOverlay(const psd_layer_effects_pattern_overlay *pattern) { ui.cmbCompositeOp->selectCompositeOp(KoID(pattern->blendMode())); ui.intOpacity->setValue(pattern->opacity()); ui.patternChooser->setCurrentPattern(pattern->pattern()); ui.chkLinkWithLayer->setChecked(pattern->alignWithLayer()); ui.intScale->setValue(pattern->scale()); } void PatternOverlay::fetchPatternOverlay(psd_layer_effects_pattern_overlay *pattern) const { pattern->setBlendMode(ui.cmbCompositeOp->selectedCompositeOp().id()); pattern->setOpacity(ui.intOpacity->value()); - pattern->setPattern(static_cast(ui.patternChooser->currentResource())); + pattern->setPattern(ui.patternChooser->currentResource().staticCast()); pattern->setAlignWithLayer(ui.chkLinkWithLayer->isChecked()); pattern->setScale(ui.intScale->value()); } /********************************************************************/ /***** Satin *********************************************/ /********************************************************************/ Satin::Satin(QWidget *parent) : QWidget(parent) { ui.setupUi(this); ui.intOpacity->setRange(0, 100); ui.intOpacity->setSuffix(i18n(" %")); ui.intDistance->setRange(0, 250); ui.intDistance->setSuffix(i18n(" px")); ui.intSize->setRange(0, 250); ui.intSize->setSuffix(i18n(" px")); connect(ui.dialAngle, SIGNAL(valueChanged(int)), SLOT(slotDialAngleChanged(int))); connect(ui.intAngle, SIGNAL(valueChanged(int)), SLOT(slotIntAngleChanged(int))); connect(ui.cmbCompositeOp, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.bnColor, SIGNAL(changed(KoColor)), SIGNAL(configChanged())); connect(ui.intOpacity, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.dialAngle, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intAngle, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intDistance, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.intSize, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.cmbContour, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.chkAntiAliased, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.chkInvert, SIGNAL(toggled(bool)), SIGNAL(configChanged())); } void Satin::slotDialAngleChanged(int value) { KisSignalsBlocker b(ui.intAngle); ui.intAngle->setValue(value); } void Satin::slotIntAngleChanged(int value) { KisSignalsBlocker b(ui.dialAngle); ui.dialAngle->setValue(value); } void Satin::setSatin(const psd_layer_effects_satin *satin) { ui.cmbCompositeOp->selectCompositeOp(KoID(satin->blendMode())); KoColor color(KoColorSpaceRegistry::instance()->rgb8()); color.fromQColor(satin->color()); ui.bnColor->setColor(color); ui.intOpacity->setValue(satin->opacity()); ui.dialAngle->setValue(satin->angle()); ui.intAngle->setValue(satin->angle()); ui.intDistance->setValue(satin->distance()); ui.intSize->setValue(satin->size()); // FIXME: Curve editing //ui.cmbContour; ui.chkAntiAliased->setChecked(satin->antiAliased()); ui.chkInvert->setChecked(satin->invert()); } void Satin::fetchSatin(psd_layer_effects_satin *satin) const { satin->setBlendMode(ui.cmbCompositeOp->selectedCompositeOp().id()); satin->setOpacity(ui.intOpacity->value()); satin->setColor(ui.bnColor->color().toQColor()); satin->setAngle(ui.dialAngle->value()); satin->setDistance(ui.intDistance->value()); satin->setSize(ui.intSize->value()); // FIXME: curve editing // ui.cmbContour; satin->setAntiAliased(ui.chkAntiAliased->isChecked()); satin->setInvert(ui.chkInvert->isChecked()); } /********************************************************************/ /***** Stroke *********************************************/ /********************************************************************/ Stroke::Stroke(KisCanvasResourceProvider *resourceProvider, QWidget *parent) : QWidget(parent), m_resourceProvider(resourceProvider) { ui.setupUi(this); ui.intSize->setRange(0, 250); ui.intSize->setSuffix(i18n(" px")); ui.intOpacity->setRange(0, 100); ui.intOpacity->setSuffix(i18n(" %")); ui.intScale->setRange(0, 100); ui.intScale->setSuffix(i18n(" %")); ui.intScale_2->setRange(0, 100); ui.intScale_2->setSuffix(i18n(" %")); connect(ui.cmbFillType, SIGNAL(currentIndexChanged(int)), ui.fillStack, SLOT(setCurrentIndex(int))); connect(ui.intSize, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.cmbPosition, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.cmbCompositeOp, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.intOpacity, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); connect(ui.cmbFillType, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.bnColor, SIGNAL(changed(KoColor)), SIGNAL(configChanged())); connect(ui.cmbGradient, SIGNAL(gradientChanged(KoAbstractGradient*)), SIGNAL(configChanged())); connect(ui.chkReverse, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.cmbStyle, SIGNAL(currentIndexChanged(int)), SIGNAL(configChanged())); connect(ui.chkAlignWithLayer, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.dialAngle, SIGNAL(valueChanged(int)), SLOT(slotDialAngleChanged(int))); connect(ui.intAngle, SIGNAL(valueChanged(int)), SLOT(slotIntAngleChanged(int))); connect(ui.intScale, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); - connect(ui.patternChooser, SIGNAL(resourceSelected(KoResource*)), SIGNAL(configChanged())); + connect(ui.patternChooser, SIGNAL(resourceSelected(KoResourceSP )), SIGNAL(configChanged())); connect(ui.chkLinkWithLayer, SIGNAL(toggled(bool)), SIGNAL(configChanged())); connect(ui.intScale_2, SIGNAL(valueChanged(int)), SIGNAL(configChanged())); // cold initialization ui.fillStack->setCurrentIndex(ui.cmbFillType->currentIndex()); } void Stroke::slotDialAngleChanged(int value) { KisSignalsBlocker b(ui.intAngle); ui.intAngle->setValue(value); } void Stroke::slotIntAngleChanged(int value) { KisSignalsBlocker b(ui.dialAngle); ui.dialAngle->setValue(value); } void Stroke::setStroke(const psd_layer_effects_stroke *stroke) { - ui.intSize->setValue(stroke->size()); ui.cmbPosition->setCurrentIndex((int)stroke->position()); ui.cmbCompositeOp->selectCompositeOp(KoID(stroke->blendMode())); ui.intOpacity->setValue(stroke->opacity()); ui.cmbFillType->setCurrentIndex((int)stroke->fillType()); KoColor color(KoColorSpaceRegistry::instance()->rgb8()); color.fromQColor(stroke->color()); ui.bnColor->setColor(color); - KoAbstractGradient *gradient = - fetchGradientLazy(GradientPointerConverter::styleToResource(stroke->gradient()), m_resourceProvider); + KoAbstractGradientSP gradient = fetchGradientLazy(GradientPointerConverter::styleToResource(stroke->gradient()), m_resourceProvider); if (gradient) { ui.cmbGradient->setGradient(gradient); } ui.chkReverse->setChecked(stroke->antiAliased()); ui.cmbStyle->setCurrentIndex((int)stroke->style()); ui.chkAlignWithLayer->setCheckable(stroke->alignWithLayer()); ui.dialAngle->setValue(stroke->angle()); ui.intAngle->setValue(stroke->angle()); ui.intScale->setValue(stroke->scale()); ui.patternChooser->setCurrentPattern(stroke->pattern()); ui.chkLinkWithLayer->setChecked(stroke->alignWithLayer()); ui.intScale_2->setValue(stroke->scale()); - } void Stroke::fetchStroke(psd_layer_effects_stroke *stroke) const { stroke->setSize(ui.intSize->value()); stroke->setPosition((psd_stroke_position)ui.cmbPosition->currentIndex()); stroke->setBlendMode(ui.cmbCompositeOp->selectedCompositeOp().id()); stroke->setOpacity(ui.intOpacity->value()); stroke->setFillType((psd_fill_type)ui.cmbFillType->currentIndex()); stroke->setColor(ui.bnColor->color().toQColor()); stroke->setGradient(GradientPointerConverter::resourceToStyle(ui.cmbGradient->gradient())); stroke->setReverse(ui.chkReverse->isChecked()); stroke->setStyle((psd_gradient_style)ui.cmbStyle->currentIndex()); stroke->setAlignWithLayer(ui.chkAlignWithLayer->isChecked()); stroke->setAngle(ui.dialAngle->value()); stroke->setScale(ui.intScale->value()); - stroke->setPattern(static_cast(ui.patternChooser->currentResource())); + stroke->setPattern(ui.patternChooser->currentResource().staticCast()); stroke->setAlignWithLayer(ui.chkLinkWithLayer->isChecked()); stroke->setScale(ui.intScale->value()); } diff --git a/libs/ui/kis_asl_layer_style_serializer.cpp b/libs/ui/kis_asl_layer_style_serializer.cpp index 981526a8d0..d0eba7b7ac 100644 --- a/libs/ui/kis_asl_layer_style_serializer.cpp +++ b/libs/ui/kis_asl_layer_style_serializer.cpp @@ -1,1235 +1,1235 @@ /* * 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.h" #include #include #include #include #include #include #include "kis_dom_utils.h" #include "psd.h" #include "kis_global.h" #include "asl/kis_asl_reader.h" #include "asl/kis_asl_xml_parser.h" #include "asl/kis_asl_writer_utils.h" #include "asl/kis_asl_xml_writer.h" #include "asl/kis_asl_writer.h" #include using namespace std::placeholders; KisAslLayerStyleSerializer::KisAslLayerStyleSerializer() { } KisAslLayerStyleSerializer::~KisAslLayerStyleSerializer() { } QVector KisAslLayerStyleSerializer::styles() const { return m_stylesVector; } void KisAslLayerStyleSerializer::setStyles(const QVector &styles) { m_stylesVector = styles; } QString compositeOpToBlendMode(const QString &compositeOp) { QString mode = "Nrml"; if (compositeOp == COMPOSITE_OVER) { mode = "Nrml"; } else if (compositeOp == COMPOSITE_DISSOLVE) { mode = "Dslv"; } else if (compositeOp == COMPOSITE_DARKEN) { mode = "Drkn"; } else if (compositeOp == COMPOSITE_MULT) { mode = "Mltp"; } else if (compositeOp == COMPOSITE_BURN) { mode = "CBrn"; } else if (compositeOp == COMPOSITE_LINEAR_BURN) { mode = "linearBurn"; } else if (compositeOp == COMPOSITE_DARKER_COLOR) { mode = "darkerColor"; } else if (compositeOp == COMPOSITE_LIGHTEN) { mode = "Lghn"; } else if (compositeOp == COMPOSITE_SCREEN) { mode = "Scrn"; } else if (compositeOp == COMPOSITE_DODGE) { mode = "CDdg"; } else if (compositeOp == COMPOSITE_LINEAR_DODGE) { mode = "linearDodge"; } else if (compositeOp == COMPOSITE_LIGHTER_COLOR) { mode = "lighterColor"; } else if (compositeOp == COMPOSITE_OVERLAY) { mode = "Ovrl"; } else if (compositeOp == COMPOSITE_SOFT_LIGHT_PHOTOSHOP) { mode = "SftL"; } else if (compositeOp == COMPOSITE_HARD_LIGHT) { mode = "HrdL"; } else if (compositeOp == COMPOSITE_VIVID_LIGHT) { mode = "vividLight"; } else if (compositeOp == COMPOSITE_LINEAR_LIGHT) { mode = "linearLight"; } else if (compositeOp == COMPOSITE_PIN_LIGHT) { mode = "pinLight"; } else if (compositeOp == COMPOSITE_HARD_MIX_PHOTOSHOP) { mode = "hardMix"; } else if (compositeOp == COMPOSITE_DIFF) { mode = "Dfrn"; } else if (compositeOp == COMPOSITE_EXCLUSION) { mode = "Xclu"; } else if (compositeOp == COMPOSITE_SUBTRACT) { mode = "Sbtr"; } else if (compositeOp == COMPOSITE_DIVIDE) { mode = "divide"; } else if (compositeOp == COMPOSITE_HUE) { mode = "H "; } else if (compositeOp == COMPOSITE_SATURATION) { mode = "Strt"; } else if (compositeOp == COMPOSITE_COLOR) { mode = "Clr "; } else if (compositeOp == COMPOSITE_LUMINIZE) { mode = "Lmns"; } else { dbgKrita << "Unknown composite op:" << mode << "Returning \"Nrml\"!"; } return mode; } QString techniqueToString(psd_technique_type technique, const QString &typeId) { QString result = "SfBL"; switch (technique) { case psd_technique_softer: result = "SfBL"; break; case psd_technique_precise: result = "PrBL"; break; case psd_technique_slope_limit: result = "Slmt"; break; } if (typeId == "BETE" && technique == psd_technique_slope_limit) { warnKrita << "WARNING: techniqueToString: invalid technique type!" << ppVar(technique) << ppVar(typeId); } return result; } QString bevelStyleToString(psd_bevel_style style) { QString result = "OtrB"; switch (style) { case psd_bevel_outer_bevel: result = "OtrB"; break; case psd_bevel_inner_bevel: result = "InrB"; break; case psd_bevel_emboss: result = "Embs"; break; case psd_bevel_pillow_emboss: result = "PlEb"; break; case psd_bevel_stroke_emboss: result = "strokeEmboss"; break; } return result; } QString gradientTypeToString(psd_gradient_style style) { QString result = "Lnr "; switch (style) { case psd_gradient_style_linear: result = "Lnr "; break; case psd_gradient_style_radial: result = "Rdl "; break; case psd_gradient_style_angle: result = "Angl"; break; case psd_gradient_style_reflected: result = "Rflc"; break; case psd_gradient_style_diamond: result = "Dmnd"; break; } return result; } QString strokePositionToString(psd_stroke_position position) { QString result = "OutF"; switch (position) { case psd_stroke_outside: result = "OutF"; break; case psd_stroke_inside: result = "InsF"; break; case psd_stroke_center: result = "CtrF"; break; } return result; } QString strokeFillTypeToString(psd_fill_type position) { QString result = "SClr"; switch (position) { case psd_fill_solid_color: result = "SClr"; break; case psd_fill_gradient: result = "GrFl"; break; case psd_fill_pattern: result = "Ptrn"; break; } return result; } -QVector KisAslLayerStyleSerializer::fetchAllPatterns(KisPSDLayerStyle *style) const +QVector KisAslLayerStyleSerializer::fetchAllPatterns(KisPSDLayerStyle *style) const { - QVector allPatterns; + QVector allPatterns; if (style->patternOverlay()->effectEnabled()) { allPatterns << style->patternOverlay()->pattern(); } if (style->stroke()->effectEnabled() && style->stroke()->fillType() == psd_fill_pattern) { allPatterns << style->stroke()->pattern(); } if(style->bevelAndEmboss()->effectEnabled() && style->bevelAndEmboss()->textureEnabled()) { allPatterns << style->bevelAndEmboss()->texturePattern(); } return allPatterns; } -QString fetchPatternUuidSafe(KoPattern *pattern, QHash patternToUuid) +QString fetchPatternUuidSafe(KoPatternSP pattern, QHash patternToUuid) { if (patternToUuid.contains(pattern)) { return patternToUuid[pattern]; } else { warnKrita << "WARNING: the pattern is not present in the Uuid map!"; return "invalid-uuid"; } } QDomDocument KisAslLayerStyleSerializer::formXmlDocument() const { KIS_ASSERT_RECOVER(!m_stylesVector.isEmpty()) { return QDomDocument(); } - QVector allPatterns; + QVector allPatterns; Q_FOREACH (KisPSDLayerStyleSP style, m_stylesVector) { allPatterns += fetchAllPatterns(style.data()); } - QHash patternToUuidMap; + QHash patternToUuidMap; KisAslXmlWriter w; if (!allPatterns.isEmpty()) { w.enterList("Patterns"); - Q_FOREACH (KoPattern *pattern, allPatterns) { + Q_FOREACH (KoPatternSP pattern, allPatterns) { if (pattern) { if (!patternToUuidMap.contains(pattern)) { QString uuid = w.writePattern("", pattern); patternToUuidMap.insert(pattern, uuid); } } else { warnKrita << "WARNING: KisAslLayerStyleSerializer::saveToDevice: saved pattern is null!"; } } w.leaveList(); } Q_FOREACH (KisPSDLayerStyleSP style, m_stylesVector) { w.enterDescriptor("", "", "null"); w.writeText("Nm ", style->name()); w.writeText("Idnt", style->psdUuid()); w.leaveDescriptor(); w.enterDescriptor("", "", "Styl"); w.enterDescriptor("documentMode", "", "documentMode"); w.leaveDescriptor(); w.enterDescriptor("Lefx", "", "Lefx"); w.writeUnitFloat("Scl ", "#Prc", 100); w.writeBoolean("masterFXSwitch", style->isEnabled()); // Drop Shadow const psd_layer_effects_drop_shadow *dropShadow = style->dropShadow(); if (dropShadow->effectEnabled()) { w.enterDescriptor("DrSh", "", "DrSh"); w.writeBoolean("enab", dropShadow->effectEnabled()); w.writeEnum("Md ", "BlnM", compositeOpToBlendMode(dropShadow->blendMode())); w.writeColor("Clr ", dropShadow->color()); w.writeUnitFloat("Opct", "#Prc", dropShadow->opacity()); w.writeBoolean("uglg", dropShadow->useGlobalLight()); w.writeUnitFloat("lagl", "#Ang", dropShadow->angle()); w.writeUnitFloat("Dstn", "#Pxl", dropShadow->distance()); w.writeUnitFloat("Ckmt", "#Pxl", dropShadow->spread()); w.writeUnitFloat("blur", "#Pxl", dropShadow->size()); w.writeUnitFloat("Nose", "#Prc", dropShadow->noise()); w.writeBoolean("AntA", dropShadow->antiAliased()); // FIXME: save curves w.writeCurve("TrnS", "Linear", QVector() << QPointF() << QPointF(255, 255)); w.writeBoolean("layerConceals", dropShadow->knocksOut()); w.leaveDescriptor(); } // Inner Shadow const psd_layer_effects_inner_shadow *innerShadow = style->innerShadow(); if (innerShadow->effectEnabled()) { w.enterDescriptor("IrSh", "", "IrSh"); w.writeBoolean("enab", innerShadow->effectEnabled()); w.writeEnum("Md ", "BlnM", compositeOpToBlendMode(innerShadow->blendMode())); w.writeColor("Clr ", innerShadow->color()); w.writeUnitFloat("Opct", "#Prc", innerShadow->opacity()); w.writeBoolean("uglg", innerShadow->useGlobalLight()); w.writeUnitFloat("lagl", "#Ang", innerShadow->angle()); w.writeUnitFloat("Dstn", "#Pxl", innerShadow->distance()); w.writeUnitFloat("Ckmt", "#Pxl", innerShadow->spread()); w.writeUnitFloat("blur", "#Pxl", innerShadow->size()); w.writeUnitFloat("Nose", "#Prc", innerShadow->noise()); w.writeBoolean("AntA", innerShadow->antiAliased()); // FIXME: save curves w.writeCurve("TrnS", "Linear", QVector() << QPointF() << QPointF(255, 255)); w.leaveDescriptor(); } // Outer Glow const psd_layer_effects_outer_glow *outerGlow = style->outerGlow(); if (outerGlow->effectEnabled()) { w.enterDescriptor("OrGl", "", "OrGl"); w.writeBoolean("enab", outerGlow->effectEnabled()); w.writeEnum("Md ", "BlnM", compositeOpToBlendMode(outerGlow->blendMode())); if (outerGlow->fillType() == psd_fill_gradient && outerGlow->gradient()) { KoSegmentGradient *segmentGradient = dynamic_cast(outerGlow->gradient().data()); KoStopGradient *stopGradient = dynamic_cast(outerGlow->gradient().data()); if (segmentGradient) { w.writeSegmentGradient("Grad", segmentGradient); } else if (stopGradient) { w.writeStopGradient("Grad", stopGradient); } else { warnKrita << "WARNING: OG: Unknown gradient type!"; w.writeColor("Clr ", outerGlow->color()); } } else { w.writeColor("Clr ", outerGlow->color()); } w.writeUnitFloat("Opct", "#Prc", outerGlow->opacity()); w.writeEnum("GlwT", "BETE", techniqueToString(outerGlow->technique(), "BETE")); w.writeUnitFloat("Ckmt", "#Pxl", outerGlow->spread()); w.writeUnitFloat("blur", "#Pxl", outerGlow->size()); w.writeUnitFloat("Nose", "#Prc", outerGlow->noise()); w.writeUnitFloat("ShdN", "#Prc", outerGlow->jitter()); w.writeBoolean("AntA", outerGlow->antiAliased()); // FIXME: save curves w.writeCurve("TrnS", "Linear", QVector() << QPointF() << QPointF(255, 255)); w.writeUnitFloat("Inpr", "#Prc", outerGlow->range()); w.leaveDescriptor(); } // Inner Glow const psd_layer_effects_inner_glow *innerGlow = style->innerGlow(); if (innerGlow->effectEnabled()) { w.enterDescriptor("IrGl", "", "IrGl"); w.writeBoolean("enab", innerGlow->effectEnabled()); w.writeEnum("Md ", "BlnM", compositeOpToBlendMode(innerGlow->blendMode())); if (innerGlow->fillType() == psd_fill_gradient && innerGlow->gradient()) { KoSegmentGradient *segmentGradient = dynamic_cast(innerGlow->gradient().data()); KoStopGradient *stopGradient = dynamic_cast(innerGlow->gradient().data()); if (segmentGradient) { w.writeSegmentGradient("Grad", segmentGradient); } else if (stopGradient) { w.writeStopGradient("Grad", stopGradient); } else { warnKrita << "WARNING: IG: Unknown gradient type!"; w.writeColor("Clr ", innerGlow->color()); } } else { w.writeColor("Clr ", innerGlow->color()); } w.writeUnitFloat("Opct", "#Prc", innerGlow->opacity()); w.writeEnum("GlwT", "BETE", techniqueToString(innerGlow->technique(), "BETE")); w.writeUnitFloat("Ckmt", "#Pxl", innerGlow->spread()); w.writeUnitFloat("blur", "#Pxl", innerGlow->size()); // NOTE: order is swapped in ASL! w.writeUnitFloat("ShdN", "#Prc", innerGlow->jitter()); w.writeUnitFloat("Nose", "#Prc", innerGlow->noise()); w.writeBoolean("AntA", innerGlow->antiAliased()); w.writeEnum("glwS", "IGSr", innerGlow->source() == psd_glow_center ? "SrcC" : "SrcE"); // FIXME: save curves w.writeCurve("TrnS", "Linear", QVector() << QPointF() << QPointF(255, 255)); w.writeUnitFloat("Inpr", "#Prc", innerGlow->range()); w.leaveDescriptor(); } // Bevel and Emboss const psd_layer_effects_bevel_emboss *bevelAndEmboss = style->bevelAndEmboss(); if (bevelAndEmboss->effectEnabled()) { w.enterDescriptor("ebbl", "", "ebbl"); w.writeBoolean("enab", bevelAndEmboss->effectEnabled()); w.writeEnum("hglM", "BlnM", compositeOpToBlendMode(bevelAndEmboss->highlightBlendMode())); w.writeColor("hglC", bevelAndEmboss->highlightColor()); w.writeUnitFloat("hglO", "#Prc", bevelAndEmboss->highlightOpacity()); w.writeEnum("sdwM", "BlnM", compositeOpToBlendMode(bevelAndEmboss->shadowBlendMode())); w.writeColor("sdwC", bevelAndEmboss->shadowColor()); w.writeUnitFloat("sdwO", "#Prc", bevelAndEmboss->shadowOpacity()); w.writeEnum("bvlT", "bvlT", techniqueToString(bevelAndEmboss->technique(), "bvlT")); w.writeEnum("bvlS", "BESl", bevelStyleToString(bevelAndEmboss->style())); w.writeBoolean("uglg", bevelAndEmboss->useGlobalLight()); w.writeUnitFloat("lagl", "#Ang", bevelAndEmboss->angle()); w.writeUnitFloat("Lald", "#Ang", bevelAndEmboss->altitude()); w.writeUnitFloat("srgR", "#Prc", bevelAndEmboss->depth()); w.writeUnitFloat("blur", "#Pxl", bevelAndEmboss->size()); w.writeEnum("bvlD", "BESs", bevelAndEmboss->direction() == psd_direction_up ? "In " : "Out "); // FIXME: save curves w.writeCurve("TrnS", "Linear", QVector() << QPointF() << QPointF(255, 255)); w.writeBoolean("antialiasGloss", bevelAndEmboss->glossAntiAliased()); w.writeUnitFloat("Sftn", "#Pxl", bevelAndEmboss->soften()); if (bevelAndEmboss->contourEnabled()) { w.writeBoolean("useShape", bevelAndEmboss->contourEnabled()); // FIXME: save curves w.writeCurve("MpgS", "Linear", QVector() << QPointF() << QPointF(255, 255)); w.writeBoolean("AntA", bevelAndEmboss->antiAliased()); w.writeUnitFloat("Inpr", "#Prc", bevelAndEmboss->contourRange()); } w.writeBoolean("useTexture", bevelAndEmboss->textureEnabled()); if (bevelAndEmboss->textureEnabled()) { w.writeBoolean("InvT", bevelAndEmboss->textureInvert()); w.writeBoolean("Algn", bevelAndEmboss->textureAlignWithLayer()); w.writeUnitFloat("Scl ", "#Prc", bevelAndEmboss->textureScale()); w.writeUnitFloat("textureDepth ", "#Prc", bevelAndEmboss->textureDepth()); w.writePatternRef("Ptrn", bevelAndEmboss->texturePattern(), fetchPatternUuidSafe(bevelAndEmboss->texturePattern(), patternToUuidMap)); w.writePhasePoint("phase", bevelAndEmboss->texturePhase()); } w.leaveDescriptor(); } // Satin const psd_layer_effects_satin *satin = style->satin(); if (satin->effectEnabled()) { w.enterDescriptor("ChFX", "", "ChFX"); w.writeBoolean("enab", satin->effectEnabled()); w.writeEnum("Md ", "BlnM", compositeOpToBlendMode(satin->blendMode())); w.writeColor("Clr ", satin->color()); w.writeBoolean("AntA", satin->antiAliased()); w.writeBoolean("Invr", satin->invert()); w.writeUnitFloat("Opct", "#Prc", satin->opacity()); w.writeUnitFloat("lagl", "#Ang", satin->angle()); w.writeUnitFloat("Dstn", "#Pxl", satin->distance()); w.writeUnitFloat("blur", "#Pxl", satin->size()); // FIXME: save curves w.writeCurve("MpgS", "Linear", QVector() << QPointF() << QPointF(255, 255)); w.leaveDescriptor(); } const psd_layer_effects_color_overlay *colorOverlay = style->colorOverlay(); if (colorOverlay->effectEnabled()) { w.enterDescriptor("SoFi", "", "SoFi"); w.writeBoolean("enab", colorOverlay->effectEnabled()); w.writeEnum("Md ", "BlnM", compositeOpToBlendMode(colorOverlay->blendMode())); w.writeUnitFloat("Opct", "#Prc", colorOverlay->opacity()); w.writeColor("Clr ", colorOverlay->color()); w.leaveDescriptor(); } // Gradient Overlay const psd_layer_effects_gradient_overlay *gradientOverlay = style->gradientOverlay(); KoSegmentGradient *segmentGradient = dynamic_cast(gradientOverlay->gradient().data()); KoStopGradient *stopGradient = dynamic_cast(gradientOverlay->gradient().data()); if (gradientOverlay->effectEnabled() && (segmentGradient || stopGradient)) { w.enterDescriptor("GrFl", "", "GrFl"); w.writeBoolean("enab", gradientOverlay->effectEnabled()); w.writeEnum("Md ", "BlnM", compositeOpToBlendMode(gradientOverlay->blendMode())); w.writeUnitFloat("Opct", "#Prc", gradientOverlay->opacity()); if (segmentGradient) { w.writeSegmentGradient("Grad", segmentGradient); } else if (stopGradient) { w.writeStopGradient("Grad", stopGradient); } w.writeUnitFloat("Angl", "#Ang", gradientOverlay->angle()); w.writeEnum("Type", "GrdT", gradientTypeToString(gradientOverlay->style())); w.writeBoolean("Rvrs", gradientOverlay->reverse()); w.writeBoolean("Algn", gradientOverlay->alignWithLayer()); w.writeUnitFloat("Scl ", "#Prc", gradientOverlay->scale()); w.writeOffsetPoint("Ofst", gradientOverlay->gradientOffset()); // FIXME: Krita doesn't support dithering w.writeBoolean("Dthr", true/*gradientOverlay->dither()*/); w.leaveDescriptor(); } // Pattern Overlay const psd_layer_effects_pattern_overlay *patternOverlay = style->patternOverlay(); if (patternOverlay->effectEnabled()) { w.enterDescriptor("patternFill", "", "patternFill"); w.writeBoolean("enab", patternOverlay->effectEnabled()); w.writeEnum("Md ", "BlnM", compositeOpToBlendMode(patternOverlay->blendMode())); w.writeUnitFloat("Opct", "#Prc", patternOverlay->opacity()); w.writePatternRef("Ptrn", patternOverlay->pattern(), fetchPatternUuidSafe(patternOverlay->pattern(), patternToUuidMap)); w.writeUnitFloat("Scl ", "#Prc", patternOverlay->scale()); w.writeBoolean("Algn", patternOverlay->alignWithLayer()); w.writePhasePoint("phase", patternOverlay->patternPhase()); w.leaveDescriptor(); } const psd_layer_effects_stroke *stroke = style->stroke(); if (stroke->effectEnabled()) { w.enterDescriptor("FrFX", "", "FrFX"); w.writeBoolean("enab", stroke->effectEnabled()); w.writeEnum("Styl", "FStl", strokePositionToString(stroke->position())); w.writeEnum("PntT", "FrFl", strokeFillTypeToString(stroke->fillType())); w.writeEnum("Md ", "BlnM", compositeOpToBlendMode(stroke->blendMode())); w.writeUnitFloat("Opct", "#Prc", stroke->opacity()); w.writeUnitFloat("Sz ", "#Pxl", stroke->size()); if (stroke->fillType() == psd_fill_solid_color) { w.writeColor("Clr ", stroke->color()); } else if (stroke->fillType() == psd_fill_gradient) { KoSegmentGradient *segmentGradient = dynamic_cast(stroke->gradient().data()); KoStopGradient *stopGradient = dynamic_cast(stroke->gradient().data()); if (segmentGradient) { w.writeSegmentGradient("Grad", segmentGradient); } else if (stopGradient) { w.writeStopGradient("Grad", stopGradient); } else { warnKrita << "WARNING: Stroke: Unknown gradient type!"; w.writeColor("Clr ", stroke->color()); } w.writeUnitFloat("Angl", "#Ang", stroke->angle()); w.writeEnum("Type", "GrdT", gradientTypeToString(stroke->style())); w.writeBoolean("Rvrs", stroke->reverse()); w.writeUnitFloat("Scl ", "#Prc", stroke->scale()); w.writeBoolean("Algn", stroke->alignWithLayer()); w.writeOffsetPoint("Ofst", stroke->gradientOffset()); // FIXME: Krita doesn't support dithering w.writeBoolean("Dthr", true/*stroke->dither()*/); } else if (stroke->fillType() == psd_fill_pattern) { w.writePatternRef("Ptrn", stroke->pattern(), fetchPatternUuidSafe(stroke->pattern(), patternToUuidMap)); w.writeUnitFloat("Scl ", "#Prc", stroke->scale()); w.writeBoolean("Lnkd", stroke->alignWithLayer()); w.writePhasePoint("phase", stroke->patternPhase()); } w.leaveDescriptor(); } w.leaveDescriptor(); w.leaveDescriptor(); } return w.document(); } inline QDomNode findNodeByClassId(const QString &classId, QDomNode parent) { return KisDomUtils::findElementByAttibute(parent, "node", "classId", classId); } void replaceAllChildren(QDomNode src, QDomNode dst) { QDomNode node; do { node = dst.lastChild(); dst.removeChild(node); } while(!node.isNull()); node = src.firstChild(); while(!node.isNull()) { dst.appendChild(node); node = src.firstChild(); } src.parentNode().removeChild(src); } QDomDocument KisAslLayerStyleSerializer::formPsdXmlDocument() const { QDomDocument doc = formXmlDocument(); QDomNode nullNode = findNodeByClassId("null", doc.documentElement()); QDomNode stylNode = findNodeByClassId("Styl", doc.documentElement()); QDomNode lefxNode = findNodeByClassId("Lefx", stylNode); replaceAllChildren(lefxNode, nullNode); return doc; } void KisAslLayerStyleSerializer::saveToDevice(QIODevice *device) { QDomDocument doc = formXmlDocument(); if (doc.isNull()) return ; KisAslWriter writer; writer.writeFile(device, doc); } void convertAndSetBlendMode(const QString &mode, boost::function setBlendMode) { QString compositeOp = COMPOSITE_OVER; if (mode == "Nrml") { compositeOp = COMPOSITE_OVER; } else if (mode == "Dslv") { compositeOp = COMPOSITE_DISSOLVE; } else if (mode == "Drkn") { compositeOp = COMPOSITE_DARKEN; } else if (mode == "Mltp") { compositeOp = COMPOSITE_MULT; } else if (mode == "CBrn") { compositeOp = COMPOSITE_BURN; } else if (mode == "linearBurn") { compositeOp = COMPOSITE_LINEAR_BURN; } else if (mode == "darkerColor") { compositeOp = COMPOSITE_DARKER_COLOR; } else if (mode == "Lghn") { compositeOp = COMPOSITE_LIGHTEN; } else if (mode == "Scrn") { compositeOp = COMPOSITE_SCREEN; } else if (mode == "CDdg") { compositeOp = COMPOSITE_DODGE; } else if (mode == "linearDodge") { compositeOp = COMPOSITE_LINEAR_DODGE; } else if (mode == "lighterColor") { compositeOp = COMPOSITE_LIGHTER_COLOR; } else if (mode == "Ovrl") { compositeOp = COMPOSITE_OVERLAY; } else if (mode == "SftL") { compositeOp = COMPOSITE_SOFT_LIGHT_PHOTOSHOP; } else if (mode == "HrdL") { compositeOp = COMPOSITE_HARD_LIGHT; } else if (mode == "vividLight") { compositeOp = COMPOSITE_VIVID_LIGHT; } else if (mode == "linearLight") { compositeOp = COMPOSITE_LINEAR_LIGHT; } else if (mode == "pinLight") { compositeOp = COMPOSITE_PIN_LIGHT; } else if (mode == "hardMix") { compositeOp = COMPOSITE_HARD_MIX_PHOTOSHOP; } else if (mode == "Dfrn") { compositeOp = COMPOSITE_DIFF; } else if (mode == "Xclu") { compositeOp = COMPOSITE_EXCLUSION; } else if (mode == "Sbtr") { compositeOp = COMPOSITE_SUBTRACT; } else if (mode == "divide") { compositeOp = COMPOSITE_DIVIDE; } else if (mode == "H ") { compositeOp = COMPOSITE_HUE; } else if (mode == "Strt") { compositeOp = COMPOSITE_SATURATION; } else if (mode == "Clr ") { compositeOp = COMPOSITE_COLOR; } else if (mode == "Lmns") { compositeOp = COMPOSITE_LUMINIZE; } else { dbgKrita << "Unknown blending mode:" << mode << "Returning COMPOSITE_OVER!"; } setBlendMode(compositeOp); } void convertAndSetCurve(const QString &name, const QVector &points, boost::function setCurveLookupTable) { Q_UNUSED(name); Q_UNUSED(points); Q_UNUSED(setCurveLookupTable); warnKrita << "convertAndSetBlendMode:" << "Curve conversion is not implemented yet"; } template void convertAndSetEnum(const QString &value, const QMap map, boost::function setMappedValue) { setMappedValue(map[value]); } inline QString _prepaddr(const QString &pref, const QString &addr) { return pref + addr; } #define CONN_TEXT_RADDR(addr, method, object, type) m_catcher.subscribeText(addr, std::bind(&type::method, object, _1)) #define CONN_COLOR(addr, method, object, type, prefix) m_catcher.subscribeColor(_prepaddr(prefix, addr), std::bind(&type::method, object, _1)) #define CONN_UNITF(addr, unit, method, object, type, prefix) m_catcher.subscribeUnitFloat(_prepaddr(prefix, addr), unit, std::bind(&type::method, object, _1)) #define CONN_BOOL(addr, method, object, type, prefix) m_catcher.subscribeBoolean(_prepaddr(prefix, addr), std::bind(&type::method, object, _1)) #define CONN_POINT(addr, method, object, type, prefix) m_catcher.subscribePoint(_prepaddr(prefix, addr), std::bind(&type::method, object, _1)) #define CONN_COMPOSITE_OP(addr, method, object, type, prefix) \ { \ boost::function setter = \ std::bind(&type::method, object, _1); \ m_catcher.subscribeEnum(_prepaddr(prefix, addr), "BlnM", std::bind(convertAndSetBlendMode, _1, setter)); \ } #define CONN_CURVE(addr, method, object, type, prefix) \ { \ boost::function setter = \ std::bind(&type::method, object, _1); \ m_catcher.subscribeCurve(_prepaddr(prefix, addr), std::bind(convertAndSetCurve, _1, _2, setter)); \ } #define CONN_ENUM(addr, tag, method, map, mapped_type, object, type, prefix) \ { \ boost::function setter = \ std::bind(&type::method, object, _1); \ m_catcher.subscribeEnum(_prepaddr(prefix, addr), tag, std::bind(convertAndSetEnum, _1, map, setter)); \ } #define CONN_GRADIENT(addr, method, object, type, prefix) \ { \ m_catcher.subscribeGradient(_prepaddr(prefix, addr), std::bind(&type::method, object, _1)); \ } #define CONN_PATTERN(addr, method, object, type, prefix) \ { \ - boost::function setter = \ + boost::function setter = \ std::bind(&type::method, object, _1); \ m_catcher.subscribePatternRef(_prepaddr(prefix, addr), std::bind(&KisAslLayerStyleSerializer::assignPatternObject, this, _1, _2, setter)); \ } -void KisAslLayerStyleSerializer::registerPatternObject(const KoPattern *pattern) { +void KisAslLayerStyleSerializer::registerPatternObject(const KoPatternSP pattern) { QString uuid = KisAslWriterUtils::getPatternUuidLazy(pattern); if (m_patternsStore.contains(uuid)) { warnKrita << "WARNING: ASL style contains a duplicated pattern!" << ppVar(pattern->name()) << ppVar(m_patternsStore[uuid]->name()); } else { KoResourceServer *server = KoResourceServerProvider::instance()->patternServer(); - KoPattern *patternToAdd = server->resourceByMD5(pattern->md5()); + KoPatternSP patternToAdd = server->resourceByMD5(pattern->md5()); if (!patternToAdd) { patternToAdd = pattern->clone(); server->addResource(patternToAdd, false); } m_patternsStore.insert(uuid, patternToAdd); } } void KisAslLayerStyleSerializer::assignPatternObject(const QString &patternUuid, const QString &patternName, - boost::function setPattern) + boost::function setPattern) { Q_UNUSED(patternName); - KoPattern *pattern = m_patternsStore[patternUuid]; + KoPatternSP pattern = m_patternsStore[patternUuid]; if (!pattern) { - warnKrita << "WARNING: ASL style contains inexistent pattern reference!"; + warnKrita << "WARNING: ASL style contains non-existent pattern reference!"; QImage dumbImage(32, 32, QImage::Format_ARGB32); dumbImage.fill(Qt::red); - KoPattern *dumbPattern = new KoPattern(dumbImage, "invalid", ""); + KoPatternSP dumbPattern(new KoPattern(dumbImage, "invalid", "")); registerPatternObject(dumbPattern); pattern = dumbPattern; } setPattern(pattern); } class FillStylesCorrector { public: static void correct(KisPSDLayerStyle *style) { correctWithoutPattern(style->outerGlow()); correctWithoutPattern(style->innerGlow()); correctWithPattern(style->stroke()); } private: template static void correctWithPattern(T *config) { if (config->pattern()) { config->setFillType(psd_fill_pattern); } else if (config->gradient()) { config->setFillType(psd_fill_gradient); } else { config->setFillType(psd_fill_solid_color); } } template static void correctWithoutPattern(T *config) { if (config->gradient()) { config->setFillType(psd_fill_gradient); } else { config->setFillType(psd_fill_solid_color); } } }; void KisAslLayerStyleSerializer::connectCatcherToStyle(KisPSDLayerStyle *style, const QString &prefix) { CONN_TEXT_RADDR("/null/Nm ", setName, style, KisPSDLayerStyle); CONN_TEXT_RADDR("/null/Idnt", setPsdUuid, style, KisPSDLayerStyle); CONN_BOOL("/masterFXSwitch", setEnabled, style, KisPSDLayerStyle, prefix); psd_layer_effects_drop_shadow *dropShadow = style->dropShadow(); CONN_COMPOSITE_OP("/DrSh/Md ", setBlendMode, dropShadow, psd_layer_effects_drop_shadow, prefix); CONN_COLOR("/DrSh/Clr ", setColor, dropShadow, psd_layer_effects_drop_shadow, prefix); CONN_UNITF("/DrSh/Opct", "#Prc", setOpacity, dropShadow, psd_layer_effects_drop_shadow, prefix); CONN_UNITF("/DrSh/lagl", "#Ang", setAngle, dropShadow, psd_layer_effects_drop_shadow, prefix); CONN_UNITF("/DrSh/Dstn", "#Pxl", setDistance, dropShadow, psd_layer_effects_drop_shadow, prefix); CONN_UNITF("/DrSh/Ckmt", "#Pxl", setSpread, dropShadow, psd_layer_effects_drop_shadow, prefix); CONN_UNITF("/DrSh/blur", "#Pxl", setSize, dropShadow, psd_layer_effects_drop_shadow, prefix); CONN_UNITF("/DrSh/Nose", "#Prc", setNoise, dropShadow, psd_layer_effects_drop_shadow, prefix); CONN_BOOL("/DrSh/enab", setEffectEnabled, dropShadow, psd_layer_effects_drop_shadow, prefix); CONN_BOOL("/DrSh/uglg", setUseGlobalLight, dropShadow, psd_layer_effects_drop_shadow, prefix); CONN_BOOL("/DrSh/AntA", setAntiAliased, dropShadow, psd_layer_effects_drop_shadow, prefix); CONN_BOOL("/DrSh/layerConceals", setKnocksOut, dropShadow, psd_layer_effects_drop_shadow, prefix); CONN_CURVE("/DrSh/TrnS", setContourLookupTable, dropShadow, psd_layer_effects_drop_shadow, prefix); psd_layer_effects_inner_shadow *innerShadow = style->innerShadow(); CONN_COMPOSITE_OP("/IrSh/Md ", setBlendMode, innerShadow, psd_layer_effects_inner_shadow, prefix); CONN_COLOR("/IrSh/Clr ", setColor, innerShadow, psd_layer_effects_inner_shadow, prefix); CONN_UNITF("/IrSh/Opct", "#Prc", setOpacity, innerShadow, psd_layer_effects_inner_shadow, prefix); CONN_UNITF("/IrSh/lagl", "#Ang", setAngle, innerShadow, psd_layer_effects_inner_shadow, prefix); CONN_UNITF("/IrSh/Dstn", "#Pxl", setDistance, innerShadow, psd_layer_effects_inner_shadow, prefix); CONN_UNITF("/IrSh/Ckmt", "#Pxl", setSpread, innerShadow, psd_layer_effects_inner_shadow, prefix); CONN_UNITF("/IrSh/blur", "#Pxl", setSize, innerShadow, psd_layer_effects_inner_shadow, prefix); CONN_UNITF("/IrSh/Nose", "#Prc", setNoise, innerShadow, psd_layer_effects_inner_shadow, prefix); CONN_BOOL("/IrSh/enab", setEffectEnabled, innerShadow, psd_layer_effects_inner_shadow, prefix); CONN_BOOL("/IrSh/uglg", setUseGlobalLight, innerShadow, psd_layer_effects_inner_shadow, prefix); CONN_BOOL("/IrSh/AntA", setAntiAliased, innerShadow, psd_layer_effects_inner_shadow, prefix); CONN_CURVE("/IrSh/TrnS", setContourLookupTable, innerShadow, psd_layer_effects_inner_shadow, prefix); psd_layer_effects_outer_glow *outerGlow = style->outerGlow(); CONN_COMPOSITE_OP("/OrGl/Md ", setBlendMode, outerGlow, psd_layer_effects_outer_glow, prefix); CONN_COLOR("/OrGl/Clr ", setColor, outerGlow, psd_layer_effects_outer_glow, prefix); CONN_UNITF("/OrGl/Opct", "#Prc", setOpacity, outerGlow, psd_layer_effects_outer_glow, prefix); CONN_UNITF("/OrGl/Ckmt", "#Pxl", setSpread, outerGlow, psd_layer_effects_outer_glow, prefix); CONN_UNITF("/OrGl/blur", "#Pxl", setSize, outerGlow, psd_layer_effects_outer_glow, prefix); CONN_UNITF("/OrGl/Nose", "#Prc", setNoise, outerGlow, psd_layer_effects_outer_glow, prefix); CONN_BOOL("/OrGl/enab", setEffectEnabled, outerGlow, psd_layer_effects_outer_glow, prefix); CONN_BOOL("/OrGl/AntA", setAntiAliased, outerGlow, psd_layer_effects_outer_glow, prefix); CONN_CURVE("/OrGl/TrnS", setContourLookupTable, outerGlow, psd_layer_effects_outer_glow, prefix); QMap fillTechniqueMap; fillTechniqueMap.insert("PrBL", psd_technique_precise); fillTechniqueMap.insert("SfBL", psd_technique_softer); CONN_ENUM("/OrGl/GlwT", "BETE", setTechnique, fillTechniqueMap, psd_technique_type, outerGlow, psd_layer_effects_outer_glow, prefix); CONN_GRADIENT("/OrGl/Grad", setGradient, outerGlow, psd_layer_effects_outer_glow, prefix); CONN_UNITF("/OrGl/Inpr", "#Prc", setRange, outerGlow, psd_layer_effects_outer_glow, prefix); CONN_UNITF("/OrGl/ShdN", "#Prc", setJitter, outerGlow, psd_layer_effects_outer_glow, prefix); psd_layer_effects_inner_glow *innerGlow = style->innerGlow(); CONN_COMPOSITE_OP("/IrGl/Md ", setBlendMode, innerGlow, psd_layer_effects_inner_glow, prefix); CONN_COLOR("/IrGl/Clr ", setColor, innerGlow, psd_layer_effects_inner_glow, prefix); CONN_UNITF("/IrGl/Opct", "#Prc", setOpacity, innerGlow, psd_layer_effects_inner_glow, prefix); CONN_UNITF("/IrGl/Ckmt", "#Pxl", setSpread, innerGlow, psd_layer_effects_inner_glow, prefix); CONN_UNITF("/IrGl/blur", "#Pxl", setSize, innerGlow, psd_layer_effects_inner_glow, prefix); CONN_UNITF("/IrGl/Nose", "#Prc", setNoise, innerGlow, psd_layer_effects_inner_glow, prefix); CONN_BOOL("/IrGl/enab", setEffectEnabled, innerGlow, psd_layer_effects_inner_glow, prefix); CONN_BOOL("/IrGl/AntA", setAntiAliased, innerGlow, psd_layer_effects_inner_glow, prefix); CONN_CURVE("/IrGl/TrnS", setContourLookupTable, innerGlow, psd_layer_effects_inner_glow, prefix); CONN_ENUM("/IrGl/GlwT", "BETE", setTechnique, fillTechniqueMap, psd_technique_type, innerGlow, psd_layer_effects_inner_glow, prefix); CONN_GRADIENT("/IrGl/Grad", setGradient, innerGlow, psd_layer_effects_inner_glow, prefix); CONN_UNITF("/IrGl/Inpr", "#Prc", setRange, innerGlow, psd_layer_effects_inner_glow, prefix); CONN_UNITF("/IrGl/ShdN", "#Prc", setJitter, innerGlow, psd_layer_effects_inner_glow, prefix); QMap glowSourceMap; glowSourceMap.insert("SrcC", psd_glow_center); glowSourceMap.insert("SrcE", psd_glow_edge); CONN_ENUM("/IrGl/glwS", "IGSr", setSource, glowSourceMap, psd_glow_source, innerGlow, psd_layer_effects_inner_glow, prefix); psd_layer_effects_satin *satin = style->satin(); CONN_COMPOSITE_OP("/ChFX/Md ", setBlendMode, satin, psd_layer_effects_satin, prefix); CONN_COLOR("/ChFX/Clr ", setColor, satin, psd_layer_effects_satin, prefix); CONN_UNITF("/ChFX/Opct", "#Prc", setOpacity, satin, psd_layer_effects_satin, prefix); CONN_UNITF("/ChFX/lagl", "#Ang", setAngle, satin, psd_layer_effects_satin, prefix); CONN_UNITF("/ChFX/Dstn", "#Pxl", setDistance, satin, psd_layer_effects_satin, prefix); CONN_UNITF("/ChFX/blur", "#Pxl", setSize, satin, psd_layer_effects_satin, prefix); CONN_BOOL("/ChFX/enab", setEffectEnabled, satin, psd_layer_effects_satin, prefix); CONN_BOOL("/ChFX/AntA", setAntiAliased, satin, psd_layer_effects_satin, prefix); CONN_BOOL("/ChFX/Invr", setInvert, satin, psd_layer_effects_satin, prefix); CONN_CURVE("/ChFX/MpgS", setContourLookupTable, satin, psd_layer_effects_satin, prefix); psd_layer_effects_color_overlay *colorOverlay = style->colorOverlay(); CONN_COMPOSITE_OP("/SoFi/Md ", setBlendMode, colorOverlay, psd_layer_effects_color_overlay, prefix); CONN_COLOR("/SoFi/Clr ", setColor, colorOverlay, psd_layer_effects_color_overlay, prefix); CONN_UNITF("/SoFi/Opct", "#Prc", setOpacity, colorOverlay, psd_layer_effects_color_overlay, prefix); CONN_BOOL("/SoFi/enab", setEffectEnabled, colorOverlay, psd_layer_effects_color_overlay, prefix); psd_layer_effects_gradient_overlay *gradientOverlay = style->gradientOverlay(); CONN_COMPOSITE_OP("/GrFl/Md ", setBlendMode, gradientOverlay, psd_layer_effects_gradient_overlay, prefix); CONN_UNITF("/GrFl/Opct", "#Prc", setOpacity, gradientOverlay, psd_layer_effects_gradient_overlay, prefix); CONN_UNITF("/GrFl/Scl ", "#Prc", setScale, gradientOverlay, psd_layer_effects_gradient_overlay, prefix); CONN_UNITF("/GrFl/Angl", "#Ang", setAngle, gradientOverlay, psd_layer_effects_gradient_overlay, prefix); CONN_BOOL("/GrFl/enab", setEffectEnabled, gradientOverlay, psd_layer_effects_gradient_overlay, prefix); // CONN_BOOL("/GrFl/Dthr", setDitherNotImplemented, gradientOverlay, psd_layer_effects_gradient_overlay, prefix); CONN_BOOL("/GrFl/Rvrs", setReverse, gradientOverlay, psd_layer_effects_gradient_overlay, prefix); CONN_BOOL("/GrFl/Algn", setAlignWithLayer, gradientOverlay, psd_layer_effects_gradient_overlay, prefix); CONN_POINT("/GrFl/Ofst", setGradientOffset, gradientOverlay, psd_layer_effects_gradient_overlay, prefix); CONN_GRADIENT("/GrFl/Grad", setGradient, gradientOverlay, psd_layer_effects_gradient_overlay, prefix); QMap gradientStyleMap; gradientStyleMap.insert("Lnr ", psd_gradient_style_linear); gradientStyleMap.insert("Rdl ", psd_gradient_style_radial); gradientStyleMap.insert("Angl", psd_gradient_style_angle); gradientStyleMap.insert("Rflc", psd_gradient_style_reflected); gradientStyleMap.insert("Dmnd", psd_gradient_style_diamond); CONN_ENUM("/GrFl/Type", "GrdT", setStyle, gradientStyleMap, psd_gradient_style, gradientOverlay, psd_layer_effects_gradient_overlay, prefix); psd_layer_effects_pattern_overlay *patternOverlay = style->patternOverlay(); CONN_BOOL("/patternFill/enab", setEffectEnabled, patternOverlay, psd_layer_effects_pattern_overlay, prefix); CONN_COMPOSITE_OP("/patternFill/Md ", setBlendMode, patternOverlay, psd_layer_effects_pattern_overlay, prefix); CONN_UNITF("/patternFill/Opct", "#Prc", setOpacity, patternOverlay, psd_layer_effects_pattern_overlay, prefix); CONN_PATTERN("/patternFill/Ptrn", setPattern, patternOverlay, psd_layer_effects_pattern_overlay, prefix); CONN_UNITF("/patternFill/Scl ", "#Prc", setScale, patternOverlay, psd_layer_effects_pattern_overlay, prefix); CONN_BOOL("/patternFill/Algn", setAlignWithLayer, patternOverlay, psd_layer_effects_pattern_overlay, prefix); CONN_POINT("/patternFill/phase", setPatternPhase, patternOverlay, psd_layer_effects_pattern_overlay, prefix); psd_layer_effects_stroke *stroke = style->stroke(); CONN_COMPOSITE_OP("/FrFX/Md ", setBlendMode, stroke, psd_layer_effects_stroke, prefix); CONN_BOOL("/FrFX/enab", setEffectEnabled, stroke, psd_layer_effects_stroke, prefix); CONN_UNITF("/FrFX/Opct", "#Prc", setOpacity, stroke, psd_layer_effects_stroke, prefix); CONN_UNITF("/FrFX/Sz ", "#Pxl", setSize, stroke, psd_layer_effects_stroke, prefix); QMap strokeStyleMap; strokeStyleMap.insert("OutF", psd_stroke_outside); strokeStyleMap.insert("InsF", psd_stroke_inside); strokeStyleMap.insert("CtrF", psd_stroke_center); CONN_ENUM("/FrFX/Styl", "FStl", setPosition, strokeStyleMap, psd_stroke_position, stroke, psd_layer_effects_stroke, prefix); QMap strokeFillType; strokeFillType.insert("SClr", psd_fill_solid_color); strokeFillType.insert("GrFl", psd_fill_gradient); strokeFillType.insert("Ptrn", psd_fill_pattern); CONN_ENUM("/FrFX/PntT", "FrFl", setFillType, strokeFillType, psd_fill_type, stroke, psd_layer_effects_stroke, prefix); // Color type CONN_COLOR("/FrFX/Clr ", setColor, stroke, psd_layer_effects_stroke, prefix); // Gradient Type CONN_GRADIENT("/FrFX/Grad", setGradient, stroke, psd_layer_effects_stroke, prefix); CONN_UNITF("/FrFX/Angl", "#Ang", setAngle, stroke, psd_layer_effects_stroke, prefix); CONN_UNITF("/FrFX/Scl ", "#Prc", setScale, stroke, psd_layer_effects_stroke, prefix); CONN_ENUM("/FrFX/Type", "GrdT", setStyle, gradientStyleMap, psd_gradient_style, stroke, psd_layer_effects_stroke, prefix); CONN_BOOL("/FrFX/Rvrs", setReverse, stroke, psd_layer_effects_stroke, prefix); CONN_BOOL("/FrFX/Algn", setAlignWithLayer, stroke, psd_layer_effects_stroke, prefix); CONN_POINT("/FrFX/Ofst", setGradientOffset, stroke, psd_layer_effects_stroke, prefix); // CONN_BOOL("/FrFX/Dthr", setDitherNotImplemented, stroke, psd_layer_effects_stroke, prefix); // Pattern type CONN_PATTERN("/FrFX/Ptrn", setPattern, stroke, psd_layer_effects_stroke, prefix); CONN_BOOL("/FrFX/Lnkd", setAlignWithLayer, stroke, psd_layer_effects_stroke, prefix); // yes, we share the params... CONN_POINT("/FrFX/phase", setPatternPhase, stroke, psd_layer_effects_stroke, prefix); psd_layer_effects_bevel_emboss *bevelAndEmboss = style->bevelAndEmboss(); CONN_BOOL("/ebbl/enab", setEffectEnabled, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_COMPOSITE_OP("/ebbl/hglM", setHighlightBlendMode, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_COLOR("/ebbl/hglC", setHighlightColor, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_UNITF("/ebbl/hglO", "#Prc", setHighlightOpacity, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_COMPOSITE_OP("/ebbl/sdwM", setShadowBlendMode, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_COLOR("/ebbl/sdwC", setShadowColor, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_UNITF("/ebbl/sdwO", "#Prc", setShadowOpacity, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); QMap bevelTechniqueMap; bevelTechniqueMap.insert("PrBL", psd_technique_precise); bevelTechniqueMap.insert("SfBL", psd_technique_softer); bevelTechniqueMap.insert("Slmt", psd_technique_slope_limit); CONN_ENUM("/ebbl/bvlT", "bvlT", setTechnique, bevelTechniqueMap, psd_technique_type, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); QMap bevelStyleMap; bevelStyleMap.insert("OtrB", psd_bevel_outer_bevel); bevelStyleMap.insert("InrB", psd_bevel_inner_bevel); bevelStyleMap.insert("Embs", psd_bevel_emboss); bevelStyleMap.insert("PlEb", psd_bevel_pillow_emboss); bevelStyleMap.insert("strokeEmboss", psd_bevel_stroke_emboss); CONN_ENUM("/ebbl/bvlS", "BESl", setStyle, bevelStyleMap, psd_bevel_style, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_BOOL("/ebbl/uglg", setUseGlobalLight, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_UNITF("/ebbl/lagl", "#Ang", setAngle, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_UNITF("/ebbl/Lald", "#Ang", setAltitude, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_UNITF("/ebbl/srgR", "#Prc", setDepth, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_UNITF("/ebbl/blur", "#Pxl", setSize, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); QMap bevelDirectionMap; bevelDirectionMap.insert("In ", psd_direction_up); bevelDirectionMap.insert("Out ", psd_direction_down); CONN_ENUM("/ebbl/bvlD", "BESs", setDirection, bevelDirectionMap, psd_direction, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_CURVE("/ebbl/TrnS", setContourLookupTable, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_BOOL("/ebbl/antialiasGloss", setGlossAntiAliased, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_UNITF("/ebbl/Sftn", "#Pxl", setSoften, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); // Use shape mode CONN_BOOL("/ebbl/useShape", setContourEnabled, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_CURVE("/ebbl/MpgS", setGlossContourLookupTable, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_BOOL("/ebbl/AntA", setAntiAliased, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_UNITF("/ebbl/Inpr", "#Prc", setContourRange, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); // Use texture mode CONN_BOOL("/ebbl/useTexture", setTextureEnabled, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_BOOL("/ebbl/InvT", setTextureInvert, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_BOOL("/ebbl/Algn", setTextureAlignWithLayer, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_UNITF("/ebbl/Scl ", "#Prc", setTextureScale, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_UNITF("/ebbl/textureDepth", "#Prc", setTextureDepth, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_PATTERN("/ebbl/Ptrn", setTexturePattern, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); CONN_POINT("/ebbl/phase", setTexturePhase, bevelAndEmboss, psd_layer_effects_bevel_emboss, prefix); } void KisAslLayerStyleSerializer::newStyleStarted(bool isPsdStructure) { m_stylesVector.append(toQShared(new KisPSDLayerStyle())); KisPSDLayerStyle *currentStyle = m_stylesVector.last().data(); psd_layer_effects_context *context = currentStyle->context(); context->keep_original = 0; QString prefix = isPsdStructure ? "/null" : "/Styl/Lefx"; connectCatcherToStyle(currentStyle, prefix); } void KisAslLayerStyleSerializer::readFromDevice(QIODevice *device) { m_stylesVector.clear(); m_catcher.subscribePattern("/Patterns/KisPattern", std::bind(&KisAslLayerStyleSerializer::registerPatternObject, this, _1)); m_catcher.subscribeNewStyleStarted(std::bind(&KisAslLayerStyleSerializer::newStyleStarted, this, false)); KisAslReader reader; QDomDocument doc = reader.readFile(device); //dbgKrita << ppVar(doc.toString()); //KisAslObjectCatcher c2; KisAslXmlParser parser; parser.parseXML(doc, m_catcher); // correct all the layer styles Q_FOREACH (KisPSDLayerStyleSP style, m_stylesVector) { FillStylesCorrector::correct(style.data()); } } void KisAslLayerStyleSerializer::registerPSDPattern(const QDomDocument &doc) { KisAslCallbackObjectCatcher catcher; catcher.subscribePattern("/Patterns/KisPattern", std::bind(&KisAslLayerStyleSerializer::registerPatternObject, this, _1)); //KisAslObjectCatcher c2; KisAslXmlParser parser; parser.parseXML(doc, catcher); } void KisAslLayerStyleSerializer::readFromPSDXML(const QDomDocument &doc) { // The caller prepares the document using th efollowing code // // KisAslReader reader; // QDomDocument doc = reader.readLfx2PsdSection(device); m_stylesVector.clear(); //m_catcher.subscribePattern("/Patterns/KisPattern", std::bind(&KisAslLayerStyleSerializer::registerPatternObject, this, _1)); m_catcher.subscribeNewStyleStarted(std::bind(&KisAslLayerStyleSerializer::newStyleStarted, this, true)); //KisAslObjectCatcher c2; KisAslXmlParser parser; parser.parseXML(doc, m_catcher); // correct all the layer styles Q_FOREACH (KisPSDLayerStyleSP style, m_stylesVector) { FillStylesCorrector::correct(style.data()); } } diff --git a/libs/ui/kis_asl_layer_style_serializer.h b/libs/ui/kis_asl_layer_style_serializer.h index 13bd8dcfe5..dc96737e5c 100644 --- a/libs/ui/kis_asl_layer_style_serializer.h +++ b/libs/ui/kis_asl_layer_style_serializer.h @@ -1,69 +1,69 @@ /* * 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. */ #ifndef __KIS_ASL_LAYER_STYLE_SERIALIZER_H #define __KIS_ASL_LAYER_STYLE_SERIALIZER_H #include "kritaui_export.h" class QIODevice; class KoPattern; #include "kis_psd_layer_style.h" #include "asl/kis_asl_callback_object_catcher.h" class KRITAUI_EXPORT KisAslLayerStyleSerializer { public: KisAslLayerStyleSerializer(); ~KisAslLayerStyleSerializer(); void saveToDevice(QIODevice *device); void readFromDevice(QIODevice *device); QVector styles() const; void setStyles(const QVector &styles); void registerPSDPattern(const QDomDocument &doc); void readFromPSDXML(const QDomDocument &doc); QDomDocument formXmlDocument() const; QDomDocument formPsdXmlDocument() const; private: - void registerPatternObject(const KoPattern *pattern); + void registerPatternObject(const KoPatternSP pattern); void assignPatternObject(const QString &patternUuid, const QString &patternName, - boost::function setPattern); + boost::function setPattern); - QVector fetchAllPatterns(KisPSDLayerStyle *style) const; + QVector fetchAllPatterns(KisPSDLayerStyle *style) const; void newStyleStarted(bool isPsdStructure); void connectCatcherToStyle(KisPSDLayerStyle *style, const QString &prefix); private: - QHash m_patternsStore; + QHash m_patternsStore; KisAslCallbackObjectCatcher m_catcher; QVector m_stylesVector; }; #endif /* __KIS_ASL_LAYER_STYLE_SERIALIZER_H */ diff --git a/libs/ui/kis_autogradient.cc b/libs/ui/kis_autogradient.cc index 5cb5fb3c0b..5a880571ac 100644 --- a/libs/ui/kis_autogradient.cc +++ b/libs/ui/kis_autogradient.cc @@ -1,172 +1,172 @@ /* * Copyright (c) 2004 Cyrille Berger * 2004 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_autogradient.h" #include #include #include #include #include #include #include "kis_debug.h" #include "KisGradientSliderWidget.h" /****************************** KisAutogradient ******************************/ -KisAutogradient::KisAutogradient(KoSegmentGradient* gradient, QWidget *parent, const char* name, const QString& caption) +KisAutogradient::KisAutogradient(KoSegmentGradientSP gradient, QWidget *parent, const char* name, const QString& caption) : QWidget(parent) , m_autogradientResource(gradient) { setObjectName(name); setupUi(this); setWindowTitle(caption); gradientSlider->setGradientResource(m_autogradientResource); nameedit->setText(gradient->name()); KoGradientSegment* segment = gradientSlider->selectedSegment(); if (segment) { slotSelectedSegment(segment); } connect(nameedit, SIGNAL(editingFinished()), this, SLOT(slotChangedName())); connect(gradientSlider, SIGNAL(sigSelectedSegment(KoGradientSegment*)), SLOT(slotSelectedSegment(KoGradientSegment*))); connect(gradientSlider, SIGNAL(sigChangedSegment(KoGradientSegment*)), SLOT(slotChangedSegment(KoGradientSegment*))); connect(comboBoxColorInterpolationType, SIGNAL(activated(int)), SLOT(slotChangedColorInterpolation(int))); connect(comboBoxInterpolationType, SIGNAL(activated(int)), SLOT(slotChangedInterpolation(int))); connect(leftColorButton, SIGNAL(changed(KoColor)), SLOT(slotChangedLeftColor(KoColor))); connect(rightColorButton, SIGNAL(changed(KoColor)), SLOT(slotChangedRightColor(KoColor))); connect(intNumInputLeftOpacity, SIGNAL(valueChanged(int)), SLOT(slotChangedLeftOpacity(int))); connect(intNumInputRightOpacity, SIGNAL(valueChanged(int)), SLOT(slotChangedRightOpacity(int))); } void KisAutogradient::activate() { paramChanged(); } void KisAutogradient::slotSelectedSegment(KoGradientSegment* segment) { leftColorButton->setColor(segment->startColor()); rightColorButton->setColor(segment->endColor()); comboBoxColorInterpolationType->setCurrentIndex(segment->colorInterpolation()); comboBoxInterpolationType->setCurrentIndex(segment->interpolation()); int leftOpacity = segment->startColor().opacityF(); intNumInputLeftOpacity->setValue(leftOpacity * 100); intNumInputLeftOpacity->setSuffix(i18n(" %")); int rightOpacity = segment->endColor().opacityF(); intNumInputRightOpacity->setValue(rightOpacity * 100); intNumInputRightOpacity->setSuffix(i18n(" %")); paramChanged(); } void KisAutogradient::slotChangedSegment(KoGradientSegment*) { paramChanged(); } void KisAutogradient::slotChangedInterpolation(int type) { KoGradientSegment* segment = gradientSlider->selectedSegment(); if (segment) segment->setInterpolation(type); gradientSlider->update(); paramChanged(); } void KisAutogradient::slotChangedColorInterpolation(int type) { KoGradientSegment* segment = gradientSlider->selectedSegment(); if (segment) segment->setColorInterpolation(type); gradientSlider->update(); paramChanged(); } void KisAutogradient::slotChangedLeftColor(const KoColor& color) { KoGradientSegment* segment = gradientSlider->selectedSegment(); if (segment) { KoColor c(color, segment->startColor().colorSpace()); c.setOpacity(segment->startColor().opacityU8()); segment->setStartColor(c); } gradientSlider->update(); paramChanged(); } void KisAutogradient::slotChangedRightColor(const KoColor& color) { KoGradientSegment* segment = gradientSlider->selectedSegment(); if (segment) { KoColor c(color, segment->endColor().colorSpace()); c.setOpacity(segment->endColor().opacityU8()); segment->setEndColor(c); } gradientSlider->repaint(); paramChanged(); } void KisAutogradient::slotChangedLeftOpacity(int value) { KoGradientSegment* segment = gradientSlider->selectedSegment(); if (segment) { KoColor c(segment->startColor(), segment->startColor().colorSpace()); c.setOpacity(qreal(value) / qreal(100.0)); segment->setStartColor(c); } gradientSlider->repaint(); paramChanged(); } void KisAutogradient::slotChangedRightOpacity(int value) { KoGradientSegment* segment = gradientSlider->selectedSegment(); if (segment) { KoColor c(segment->endColor(), segment->endColor().colorSpace()); c.setOpacity(quint8((value *OPACITY_OPAQUE_U8) / 100)); segment->setEndColor(c); } gradientSlider->repaint(); paramChanged(); } void KisAutogradient::slotChangedName() { m_autogradientResource->setName(nameedit->text()); } void KisAutogradient::paramChanged() { m_autogradientResource->updatePreview(); } diff --git a/libs/ui/kis_autogradient.h b/libs/ui/kis_autogradient.h index 0684fe7a80..3495808175 100644 --- a/libs/ui/kis_autogradient.h +++ b/libs/ui/kis_autogradient.h @@ -1,50 +1,50 @@ /* * Copyright (c) 2004 Cyrille Berger * 2004 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KIS_AUTOGRADIENT_H_ #define _KIS_AUTOGRADIENT_H_ #include "ui_wdgautogradient.h" class KoGradientSegment; -class KoSegmentGradient; +#include class KisAutogradient : public QWidget, public Ui::KisWdgAutogradient { Q_OBJECT public: - KisAutogradient(KoSegmentGradient* gradient, QWidget *parent, const char* name, const QString& caption); + KisAutogradient(KoSegmentGradientSP gradient, QWidget *parent, const char* name, const QString& caption); void activate(); private: - KoSegmentGradient* m_autogradientResource; + KoSegmentGradientSP m_autogradientResource; private Q_SLOTS: void slotSelectedSegment(KoGradientSegment* segment); void slotChangedSegment(KoGradientSegment* segment); void slotChangedInterpolation(int type); void slotChangedColorInterpolation(int type); void slotChangedLeftColor(const KoColor& color); void slotChangedRightColor(const KoColor& color); void slotChangedLeftOpacity(int value); void slotChangedRightOpacity(int value); void slotChangedName(); void paramChanged(); }; #endif diff --git a/libs/ui/kis_canvas_resource_provider.cpp b/libs/ui/kis_canvas_resource_provider.cpp index 23d0d34532..593ac29a68 100644 --- a/libs/ui/kis_canvas_resource_provider.cpp +++ b/libs/ui/kis_canvas_resource_provider.cpp @@ -1,546 +1,546 @@ /* * 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; m_enablefGChange = true; // default to true, so that colour history is working without popup palette } 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); } KoCanvasBase * KisCanvasResourceProvider::canvas() const { return m_view->canvasBase(); } KoColor KisCanvasResourceProvider::bgColor() const { return m_resourceManager->resource(KoCanvasResourceProvider::BackgroundColor).value(); } KoColor KisCanvasResourceProvider::fgColor() const { return m_resourceManager->resource(KoCanvasResourceProvider::ForegroundColor).value(); } float KisCanvasResourceProvider::HDRExposure() const { return static_cast(m_resourceManager->resource(HdrExposure).toDouble()); } void KisCanvasResourceProvider::setHDRExposure(float exposure) { m_resourceManager->setResource(HdrExposure, static_cast(exposure)); } float KisCanvasResourceProvider::HDRGamma() const { return static_cast(m_resourceManager->resource(HdrGamma).toDouble()); } void KisCanvasResourceProvider::setHDRGamma(float gamma) { m_resourceManager->setResource(HdrGamma, static_cast(gamma)); } -KoPattern * KisCanvasResourceProvider::currentPattern() const +KoPatternSP KisCanvasResourceProvider::currentPattern() const { if (m_resourceManager->hasResource(CurrentPattern)) { - return m_resourceManager->resource(CurrentPattern).value(); + return m_resourceManager->resource(CurrentPattern).value(); } else { return 0; } } -KoAbstractGradient* KisCanvasResourceProvider::currentGradient() const +KoAbstractGradientSP KisCanvasResourceProvider::currentGradient() const { if (m_resourceManager->hasResource(CurrentGradient)) { - return m_resourceManager->resource(CurrentGradient).value(); + return m_resourceManager->resource(CurrentGradient).value(); } else { return 0; } } KisImageWSP KisCanvasResourceProvider::currentImage() const { return m_view->image(); } KisNodeSP KisCanvasResourceProvider::currentNode() const { return m_view->activeNode(); } -KoGamutMask *KisCanvasResourceProvider::currentGamutMask() const +KoGamutMaskSP KisCanvasResourceProvider::currentGamutMask() const { if (m_resourceManager->hasResource(CurrentGamutMask)) { - return m_resourceManager->resource(CurrentGamutMask).value(); + return m_resourceManager->resource(CurrentGamutMask).value(); } else { return nullptr; } } KisPaintOpPresetSP KisCanvasResourceProvider::currentPreset() const { KisPaintOpPresetSP preset = m_resourceManager->resource(CurrentPaintOpPreset).value(); return preset; } void KisCanvasResourceProvider::setPaintOpPreset(const KisPaintOpPresetSP preset) { Q_ASSERT(preset->valid()); Q_ASSERT(!preset->paintOp().id().isEmpty()); Q_ASSERT(preset->settings()); if (!preset) return; dbgUI << "setPaintOpPreset" << preset->paintOp(); QVariant v; v.setValue(preset); m_resourceManager->setResource(CurrentPaintOpPreset, v); } KisPaintOpPresetSP KisCanvasResourceProvider::previousPreset() const { KisPaintOpPresetSP preset = m_resourceManager->resource(PreviousPaintOpPreset).value(); return preset; } void KisCanvasResourceProvider::setPreviousPaintOpPreset(const KisPaintOpPresetSP preset) { Q_ASSERT(preset->valid()); Q_ASSERT(!preset->paintOp().id().isEmpty()); Q_ASSERT(preset->settings()); if (!preset) return; dbgUI << "setPreviousPaintOpPreset" << preset->paintOp(); QVariant v; v.setValue(preset); m_resourceManager->setResource(PreviousPaintOpPreset, v); } -void KisCanvasResourceProvider::slotPatternActivated(KoResource * res) +void KisCanvasResourceProvider::slotPatternActivated(KoResourceSP res) { - KoPattern *pattern = dynamic_cast(res); + KoPatternSP pattern = res.dynamicCast(); QVariant v; - v.setValue(pattern); + v.setValue(pattern); m_resourceManager->setResource(CurrentPattern, v); emit sigPatternChanged(pattern); } -void KisCanvasResourceProvider::slotGradientActivated(KoResource *res) +void KisCanvasResourceProvider::slotGradientActivated(KoResourceSP res) { - KoAbstractGradient * gradient = dynamic_cast(res); + KoAbstractGradientSP gradient = res.dynamicCast(); QVariant v; - v.setValue(gradient); + v.setValue(gradient); m_resourceManager->setResource(CurrentGradient, v); emit sigGradientChanged(gradient); } void KisCanvasResourceProvider::setBGColor(const KoColor& c) { QVariant v; v.setValue(c); m_resourceManager->setResource(KoCanvasResourceProvider::BackgroundColor, v); emit sigBGColorChanged(c); } void KisCanvasResourceProvider::setFGColor(const KoColor& c) { m_fGChanged = true; QVariant v; v.setValue(c); m_resourceManager->setResource(KoCanvasResourceProvider::ForegroundColor, v); emit sigFGColorChanged(c); } void KisCanvasResourceProvider::slotSetFGColor(const KoColor& c) { setFGColor(c); } void KisCanvasResourceProvider::slotSetBGColor(const KoColor& c) { setBGColor(c); } void KisCanvasResourceProvider::slotNodeActivated(const KisNodeSP node) { QVariant v; v.setValue(KisNodeWSP(node)); m_resourceManager->setResource(CurrentKritaNode, v); emit sigNodeChanged(currentNode()); } void KisCanvasResourceProvider::slotImageSizeChanged() { if (KisImageWSP image = m_view->image()) { float fw = image->width() / image->xRes(); float fh = image->height() / image->yRes(); QSizeF postscriptSize(fw, fh); m_resourceManager->setResource(KoCanvasResourceProvider::PageSize, postscriptSize); } } void KisCanvasResourceProvider::slotOnScreenResolutionChanged() { KisImageWSP image = m_view->image(); KisCanvas2 *canvas = m_view->canvasBase(); if(!image || !canvas) return; qreal zoomX, zoomY; canvas->coordinatesConverter()->zoom(&zoomX, &zoomY); qreal scaleX = zoomX / image->xRes(); qreal scaleY = zoomY / image->yRes(); emit sigOnScreenResolutionChanged(scaleX, scaleY); } void KisCanvasResourceProvider::slotCanvasResourceChanged(int key, const QVariant & res) { if(key == KoCanvasResourceProvider::ForegroundColor || key == KoCanvasResourceProvider::BackgroundColor) { - KoAbstractGradient* resource = KoResourceServerProvider::instance()->gradientServer()->resources()[0]; - KoStopGradient* stopGradient = dynamic_cast(resource); + KoAbstractGradientSP resource = KoResourceServerProvider::instance()->gradientServer()->resources()[0]; + KoStopGradientSP stopGradient = resource.dynamicCast(); if(stopGradient) { QList stops; stops << KoGradientStop(0.0, fgColor()) << KoGradientStop(1.0, KoColor(QColor(0, 0, 0, 0), fgColor().colorSpace())); stopGradient->setStops(stops); KoResourceServerProvider::instance()->gradientServer()->updateResource(resource); } resource = KoResourceServerProvider::instance()->gradientServer()->resources()[1]; - stopGradient = dynamic_cast(resource); + stopGradient = resource.dynamicCast(); if(stopGradient) { QList stops; stops << KoGradientStop(0.0, fgColor()) << KoGradientStop(1.0, bgColor()); stopGradient->setStops(stops); KoResourceServerProvider::instance()->gradientServer()->updateResource(resource); } } switch (key) { case(KoCanvasResourceProvider::ForegroundColor): m_fGChanged = true; emit sigFGColorChanged(res.value()); break; case(KoCanvasResourceProvider::BackgroundColor): emit sigBGColorChanged(res.value()); break; case(CurrentPattern): - emit sigPatternChanged(static_cast(res.value())); + emit sigPatternChanged(res.value()); break; case(CurrentGradient): - emit sigGradientChanged(static_cast(res.value())); + 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 && m_enablefGChange) { emit sigFGColorUsed(fgColor()); m_fGChanged = false; } } -void KisCanvasResourceProvider::slotGamutMaskActivated(KoGamutMask *mask) +void KisCanvasResourceProvider::slotGamutMaskActivated(KoGamutMaskSP mask) { QVariant v; - v.setValue(mask); + v.setValue(mask); m_resourceManager->setResource(CurrentGamutMask, v); emit sigGamutMaskChanged(mask); } void KisCanvasResourceProvider::slotGamutMaskUnset() { m_resourceManager->clearResource(CurrentGamutMask); emit sigGamutMaskUnset(); } void KisCanvasResourceProvider::slotGamutMaskPreviewUpdate() { emit sigGamutMaskPreviewUpdate(); } void KisCanvasResourceProvider::slotResetEnableFGChange(bool b) { m_enablefGChange = b; } 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::setGlobalAlphaLock(bool lock) { m_resourceManager->setResource(GlobalAlphaLock, lock); } bool KisCanvasResourceProvider::globalAlphaLock() const { return m_resourceManager->resource(GlobalAlphaLock).toBool(); } void KisCanvasResourceProvider::setDisablePressure(bool value) { m_resourceManager->setResource(DisablePressure, value); } bool KisCanvasResourceProvider::disablePressure() const { return m_resourceManager->resource(DisablePressure).toBool(); } -void KisCanvasResourceProvider::notifyLoadingWorkspace(KisWorkspaceResource* workspace) +void KisCanvasResourceProvider::notifyLoadingWorkspace(KisWorkspaceResourceSP workspace) { emit sigLoadingWorkspace(workspace); } -void KisCanvasResourceProvider::notifySavingWorkspace(KisWorkspaceResource* workspace) +void KisCanvasResourceProvider::notifySavingWorkspace(KisWorkspaceResourceSP workspace) { emit sigSavingWorkspace(workspace); } diff --git a/libs/ui/kis_canvas_resource_provider.h b/libs/ui/kis_canvas_resource_provider.h index 5cfb97dace..8e7216c6dd 100644 --- a/libs/ui/kis_canvas_resource_provider.h +++ b/libs/ui/kis_canvas_resource_provider.h @@ -1,246 +1,249 @@ /* * 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. */ #ifndef KIS_CANVAS_RESOURCE_PROVIDER_H_ #define KIS_CANVAS_RESOURCE_PROVIDER_H_ #include #include #include #include +#include #include "kis_types.h" #include "kritaui_export.h" -class KisWorkspaceResource; +#include +#include +#include +#include + class KoColorProfile; class KoAbstractGradient; -class KoResource; class KoCanvasBase; class KisViewManager; -class KoPattern; -class KoGamutMask; + class KisFilterConfiguration; #include /** * KisCanvasResourceProvider contains the per-window current settings that * influence painting, like paintop, color, gradients and so on. */ class KRITAUI_EXPORT KisCanvasResourceProvider : public QObject { Q_OBJECT public: enum Resources { HdrExposure = KoCanvasResourceProvider::KritaStart + 1, CurrentPattern, CurrentGamutMask, CurrentGradient, CurrentDisplayProfile, CurrentKritaNode, CurrentPaintOpPreset, CurrentGeneratorConfiguration, CurrentCompositeOp, CurrentEffectiveCompositeOp, LodAvailability, ///<-user choice LodSizeThreshold, ///<-user choice LodSizeThresholdSupported, ///<-paintop property EffectiveLodAvailablility, ///<- a superposition of user choice, threshold and paintop traits EraserMode, MirrorHorizontal, MirrorVertical, MirrorHorizontalLock, MirrorVerticalLock, MirrorVerticalHideDecorations, MirrorHorizontalHideDecorations, Opacity, Flow, Size, HdrGamma, GlobalAlphaLock, DisablePressure, PreviousPaintOpPreset, EffectiveZoom ///<-Used only by painting tools for non-displaying purposes }; KisCanvasResourceProvider(KisViewManager * view); ~KisCanvasResourceProvider() override; void setResourceManager(KoCanvasResourceProvider *resourceManager); KoCanvasResourceProvider* resourceManager(); KoCanvasBase * canvas() const; KoColor bgColor() const; void setBGColor(const KoColor& c); KoColor fgColor() const; void setFGColor(const KoColor& c); float HDRExposure() const; void setHDRExposure(float exposure); float HDRGamma() const; void setHDRGamma(float gamma); bool eraserMode() const; void setEraserMode(bool value); - KoPattern *currentPattern() const; + KoPatternSP currentPattern() const; - KoAbstractGradient *currentGradient() const; + KoAbstractGradientSP currentGradient() const; KisImageWSP currentImage() const; KisNodeSP currentNode() const; - KoGamutMask* currentGamutMask() const; + KoGamutMaskSP currentGamutMask() const; KisPaintOpPresetSP currentPreset() const; void setPaintOpPreset(const KisPaintOpPresetSP preset); KisPaintOpPresetSP previousPreset() const; void setPreviousPaintOpPreset(const KisPaintOpPresetSP preset); void setCurrentCompositeOp(const QString& compositeOp); QString currentCompositeOp() const; QList > perspectiveGrids() const; void addPerspectiveGrid(KisAbstractPerspectiveGrid*); void removePerspectiveGrid(KisAbstractPerspectiveGrid*); void clearPerspectiveGrids(); void setMirrorHorizontal(bool mirrorHorizontal); bool mirrorHorizontal() const; void setMirrorVertical(bool mirrorVertical); bool mirrorVertical() const; // options for horizontal and vertical mirror toolbar void setMirrorHorizontalLock(bool isLocked); bool mirrorHorizontalLock(); void setMirrorVerticalLock(bool isLocked); bool mirrorVerticalLock(); void setMirrorVerticalHideDecorations(bool hide); bool mirrorVerticalHideDecorations(); void setMirrorHorizontalHideDecorations(bool hide); bool mirrorHorizontalHideDecorations(); void mirrorVerticalMoveCanvasToCenter(); void mirrorHorizontalMoveCanvasToCenter(); void setOpacity(qreal opacity); qreal opacity() const; void setFlow(qreal opacity); qreal flow() const; void setSize(qreal size); qreal size() const; void setGlobalAlphaLock(bool lock); bool globalAlphaLock() const; void setDisablePressure(bool value); bool disablePressure() const; ///Notify that the workspace is saved and settings should be saved to it - void notifySavingWorkspace(KisWorkspaceResource* workspace); + void notifySavingWorkspace(KisWorkspaceResourceSP workspace); ///Notify that the workspace is loaded and settings can be read - void notifyLoadingWorkspace(KisWorkspaceResource* workspace); + void notifyLoadingWorkspace(KisWorkspaceResourceSP workspace); public Q_SLOTS: void slotSetFGColor(const KoColor& c); void slotSetBGColor(const KoColor& c); - void slotPatternActivated(KoResource *pattern); - void slotGradientActivated(KoResource *gradient); + void slotPatternActivated(KoResourceSP pattern); + void slotGradientActivated(KoResourceSP gradient); void slotNodeActivated(const KisNodeSP node); void slotPainting(); - void slotGamutMaskActivated(KoGamutMask* mask); + void slotGamutMaskActivated(KoGamutMaskSP mask); void slotGamutMaskUnset(); void slotGamutMaskPreviewUpdate(); /** * Set the image size in pixels. The resource provider will store * the image size in postscript points. */ // FIXME: this slot doesn't catch the case when image resolution is changed void slotImageSizeChanged(); void slotOnScreenResolutionChanged(); // This is a flag to handle a bug: // If pop up palette is visible and a new colour is selected, the new colour // will be added when the user clicks on the canvas to hide the palette // In general, we want to be able to store recent color if the pop up palette // is not visible void slotResetEnableFGChange(bool); private Q_SLOTS: void slotCanvasResourceChanged(int key, const QVariant & res); Q_SIGNALS: void sigFGColorChanged(const KoColor &); void sigBGColorChanged(const KoColor &); - void sigGradientChanged(KoAbstractGradient *); - void sigPatternChanged(KoPattern *); + void sigGradientChanged(KoAbstractGradientSP); + void sigPatternChanged(KoPatternSP); void sigNodeChanged(const KisNodeSP); void sigDisplayProfileChanged(const KoColorProfile *); void sigFGColorUsed(const KoColor&); void sigOnScreenResolutionChanged(qreal scaleX, qreal scaleY); void sigOpacityChanged(qreal); - void sigSavingWorkspace(KisWorkspaceResource* workspace); - void sigLoadingWorkspace(KisWorkspaceResource* workspace); + void sigSavingWorkspace(KisWorkspaceResourceSP workspace); + void sigLoadingWorkspace(KisWorkspaceResourceSP workspace); void mirrorModeChanged(); void moveMirrorVerticalCenter(); void moveMirrorHorizontalCenter(); - void sigGamutMaskChanged(KoGamutMask* mask); + void sigGamutMaskChanged(KoGamutMaskSP mask); void sigGamutMaskUnset(); void sigGamutMaskPreviewUpdate(); private: KisViewManager * m_view; KoCanvasResourceProvider *m_resourceManager; bool m_fGChanged; QList > m_perspectiveGrids; // This is a flag to handle a bug: // If pop up palette is visible and a new colour is selected, the new colour // will be added when the user clicks on the canvas to hide the palette // In general, we want to be able to store recent color if the pop up palette // is not visible bool m_enablefGChange; }; #endif diff --git a/libs/ui/kis_control_frame.cpp b/libs/ui/kis_control_frame.cpp index 57722d1547..fe446ecb0b 100644 --- a/libs/ui/kis_control_frame.cpp +++ b/libs/ui/kis_control_frame.cpp @@ -1,243 +1,243 @@ /* * kis_control_frame.cc - part of Krita * * Copyright (c) 1999 Matthias Elter * Copyright (c) 2003 Patrick Julien * Copyright (c) 2004 Sven Langkamp * Copyright (c) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details.g * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_control_frame.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisResourceServerProvider.h" #include "kis_canvas_resource_provider.h" #include "widgets/kis_iconwidget.h" #include "widgets/kis_gradient_chooser.h" #include "KisViewManager.h" #include "kis_config.h" #include "kis_paintop_box.h" #include "kis_custom_pattern.h" #include "widgets/kis_pattern_chooser.h" #include "kis_favorite_resource_manager.h" #include "kis_display_color_converter.h" #include KisControlFrame::KisControlFrame(KisViewManager *view, QWidget *parent, const char* name) : QObject(view) , m_viewManager(view) , m_patternWidget(0) , m_gradientWidget(0) , m_patternChooserPopup(0) , m_gradientChooserPopup(0) , m_paintopBox(0) { setObjectName(name); m_font = QFontDatabase::systemFont(QFontDatabase::GeneralFont); m_patternWidget = new KisIconWidget(parent, "patterns"); m_patternWidget->setToolTip(i18n("Fill Patterns")); m_patternWidget->setFixedSize(32, 32); m_gradientWidget = new KisIconWidget(parent, "gradients"); m_gradientWidget->setToolTip(i18n("Gradients")); m_gradientWidget->setFixedSize(32, 32); KoResourceServer * rserver = KoResourceServerProvider::instance()->gradientServer(); QSharedPointer adapter (new KoResourceServerAdapter(rserver)); m_gradientWidget->setResourceAdapter(adapter); } void KisControlFrame::setup(QWidget *parent) { createPatternsChooser(m_viewManager); createGradientsChooser(m_viewManager); QWidgetAction *action = new QWidgetAction(this); action->setText(i18n("&Patterns")); m_viewManager->actionCollection()->addAction("patterns", action); action->setDefaultWidget(m_patternWidget); action = new QWidgetAction(this); action->setText(i18n("&Gradients")); m_viewManager->actionCollection()->addAction("gradients", action); action->setDefaultWidget(m_gradientWidget); // XXX: KOMVC we don't have a canvas here yet, needs a setImageView const KoColorDisplayRendererInterface *displayRenderer = \ KisDisplayColorConverter::dumbConverterInstance()->displayRendererInterface(); m_dual = new KoDualColorButton(m_viewManager->resourceProvider()->fgColor(), m_viewManager->resourceProvider()->bgColor(), displayRenderer, m_viewManager->mainWindow(), m_viewManager->mainWindow()); m_dual->setPopDialog(true); action = new QWidgetAction(this); action->setText(i18n("&Color")); m_viewManager->actionCollection()->addAction("dual", action); action->setDefaultWidget(m_dual); connect(m_dual, SIGNAL(foregroundColorChanged(KoColor)), m_viewManager->resourceProvider(), SLOT(slotSetFGColor(KoColor))); connect(m_dual, SIGNAL(backgroundColorChanged(KoColor)), m_viewManager->resourceProvider(), SLOT(slotSetBGColor(KoColor))); connect(m_viewManager->resourceProvider(), SIGNAL(sigFGColorChanged(KoColor)), m_dual, SLOT(setForegroundColor(KoColor))); connect(m_viewManager->resourceProvider(), SIGNAL(sigBGColorChanged(KoColor)), m_dual, SLOT(setBackgroundColor(KoColor))); connect(m_viewManager->resourceProvider(), SIGNAL(sigFGColorChanged(KoColor)), m_gradientWidget, SLOT(update())); connect(m_viewManager->resourceProvider(), SIGNAL(sigBGColorChanged(KoColor)), m_gradientWidget, SLOT(update())); m_dual->setFixedSize(28, 28); connect(m_viewManager, SIGNAL(viewChanged()), SLOT(slotUpdateDisplayRenderer())); m_paintopBox = new KisPaintopBox(m_viewManager, parent, "paintopbox"); action = new QWidgetAction(this); action->setText(i18n("&Painter's Tools")); m_viewManager->actionCollection()->addAction("paintops", action); action->setDefaultWidget(m_paintopBox); } void KisControlFrame::slotUpdateDisplayRenderer() { if (m_viewManager->canvasBase()){ m_dual->setDisplayRenderer(m_viewManager->canvasBase()->displayColorConverter()->displayRendererInterface()); m_dual->setColorSpace(m_viewManager->canvasBase()->image()->colorSpace()); m_viewManager->canvasBase()->image()->disconnect(m_dual); connect(m_viewManager->canvasBase()->image(), SIGNAL(sigColorSpaceChanged(const KoColorSpace*)), m_dual, SLOT(setColorSpace(const KoColorSpace*)), Qt::UniqueConnection); } else if (m_viewManager->viewCount()==0) { m_dual->setDisplayRenderer(); } } -void KisControlFrame::slotSetPattern(KoPattern * pattern) +void KisControlFrame::slotSetPattern(KoPatternSP pattern) { m_patternWidget->slotSetItem(pattern); m_patternChooser->setCurrentPattern(pattern); } -void KisControlFrame::slotSetGradient(KoAbstractGradient * gradient) +void KisControlFrame::slotSetGradient(KoAbstractGradientSP gradient) { m_gradientWidget->slotSetItem(gradient); } void KisControlFrame::createPatternsChooser(KisViewManager * view) { if (m_patternChooserPopup) delete m_patternChooserPopup; m_patternChooserPopup = new QWidget(m_patternWidget); m_patternChooserPopup->setObjectName("pattern_chooser_popup"); QHBoxLayout * l2 = new QHBoxLayout(m_patternChooserPopup); l2->setObjectName("patternpopuplayout"); m_patternsTab = new QTabWidget(m_patternChooserPopup); m_patternsTab->setObjectName("patternstab"); m_patternsTab->setFocusPolicy(Qt::NoFocus); m_patternsTab->setFont(m_font); l2->addWidget(m_patternsTab); m_patternChooser = new KisPatternChooser(m_patternChooserPopup); m_patternChooser->setFont(m_font); QWidget *patternChooserPage = new QWidget(m_patternChooserPopup); QHBoxLayout *patternChooserPageLayout = new QHBoxLayout(patternChooserPage); patternChooserPageLayout->addWidget(m_patternChooser); m_patternsTab->addTab(patternChooserPage, i18n("Patterns")); KisCustomPattern* customPatterns = new KisCustomPattern(0, "custompatterns", i18n("Custom Pattern"), m_viewManager); customPatterns->setFont(m_font); m_patternsTab->addTab(customPatterns, i18n("Custom Pattern")); - connect(m_patternChooser, SIGNAL(resourceSelected(KoResource*)), - view->resourceProvider(), SLOT(slotPatternActivated(KoResource*))); + connect(m_patternChooser, SIGNAL(resourceSelected(KoResourceSP )), + view->resourceProvider(), SLOT(slotPatternActivated(KoResourceSP ))); - connect(customPatterns, SIGNAL(activatedResource(KoResource*)), - view->resourceProvider(), SLOT(slotPatternActivated(KoResource*))); + connect(customPatterns, SIGNAL(activatedResource(KoResourceSP )), + view->resourceProvider(), SLOT(slotPatternActivated(KoResourceSP ))); - connect(view->resourceProvider(), SIGNAL(sigPatternChanged(KoPattern*)), - this, SLOT(slotSetPattern(KoPattern*))); + connect(view->resourceProvider(), SIGNAL(sigPatternChanged(KoPatternSP)), + this, SLOT(slotSetPattern(KoPatternSP))); m_patternChooser->setCurrentItem(0, 0); if (m_patternChooser->currentResource() && view->resourceProvider()) { view->resourceProvider()->slotPatternActivated(m_patternChooser->currentResource()); } m_patternWidget->setPopupWidget(m_patternChooserPopup); } void KisControlFrame::createGradientsChooser(KisViewManager * view) { if (m_gradientChooserPopup) { delete m_gradientChooserPopup; m_gradientChooserPopup = 0; } m_gradientChooserPopup = new QWidget(m_gradientWidget); m_gradientChooserPopup->setObjectName("gradient_chooser_popup"); QHBoxLayout * l2 = new QHBoxLayout(m_gradientChooserPopup); l2->setObjectName("gradientpopuplayout"); m_gradientTab = new QTabWidget(m_gradientChooserPopup); m_gradientTab->setObjectName("gradientstab"); m_gradientTab->setFocusPolicy(Qt::NoFocus); m_gradientTab->setFont(m_font); l2->addWidget(m_gradientTab); m_gradientChooser = new KisGradientChooser(m_gradientChooserPopup); m_gradientChooser->setFont(m_font); m_gradientTab->addTab(m_gradientChooser, i18n("Gradients")); - connect(m_gradientChooser, SIGNAL(resourceSelected(KoResource*)), - view->resourceProvider(), SLOT(slotGradientActivated(KoResource*))); + connect(m_gradientChooser, SIGNAL(resourceSelected(KoResourceSP )), + view->resourceProvider(), SLOT(slotGradientActivated(KoResourceSP ))); connect (view->mainWindow(), SIGNAL(themeChanged()), m_gradientChooser, SLOT(slotUpdateIcons())); connect(view->resourceProvider(), SIGNAL(sigGradientChanged(KoAbstractGradient*)), this, SLOT(slotSetGradient(KoAbstractGradient*))); m_gradientChooser->setCurrentItem(0, 0); if (m_gradientChooser->currentResource() && view->resourceProvider()) view->resourceProvider()->slotGradientActivated(m_gradientChooser->currentResource()); m_gradientWidget->setPopupWidget(m_gradientChooserPopup); } diff --git a/libs/ui/kis_control_frame.h b/libs/ui/kis_control_frame.h index 71fc9433cc..3eb3aec75d 100644 --- a/libs/ui/kis_control_frame.h +++ b/libs/ui/kis_control_frame.h @@ -1,95 +1,96 @@ /* * kis_control_frame.h - part of Krita * * Copyright (c) 1999 Matthias Elter * Copyright (c) 2003 Patrick Julien * Copyright (c) 2004 Sven Langkamp * Copyright (c) 2003-2008 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. */ #ifndef __kis_control_frame_h__ #define __kis_control_frame_h__ #include #include #include +#include +#include + class QWidget; class QTabWidget; -class KoAbstractGradient; class KisGradientChooser; class KisPatternChooser; class KisPaintopBox; class KisViewManager; class KisIconWidget; -class KoPattern; class KoDualColorButton; /** * Control Frame - status display with access to * color selector, gradient, patterns, and paintop presets */ class KisControlFrame : public QObject { Q_OBJECT public: KisControlFrame(KisViewManager *view, QWidget *parent = 0, const char *name = 0); ~KisControlFrame() override {} void setup(QWidget *parent); KisPaintopBox* paintopBox() { return m_paintopBox; } private Q_SLOTS: - void slotSetPattern(KoPattern * pattern); - void slotSetGradient(KoAbstractGradient * gradient); + void slotSetPattern(KoPatternSP pattern); + void slotSetGradient(KoAbstractGradientSP gradient); void slotUpdateDisplayRenderer(); private: void createPatternsChooser(KisViewManager * view); void createGradientsChooser(KisViewManager * view); private: QFont m_font; KisViewManager *m_viewManager; QTabWidget *m_gradientTab; QTabWidget *m_patternsTab; KisIconWidget *m_patternWidget; KisIconWidget *m_gradientWidget; QWidget *m_patternChooserPopup; QWidget *m_gradientChooserPopup; KisGradientChooser *m_gradientChooser; KisPatternChooser *m_patternChooser; KisPaintopBox *m_paintopBox; KoDualColorButton *m_dual; }; #endif diff --git a/libs/ui/kis_custom_pattern.cc b/libs/ui/kis_custom_pattern.cc index 610cedf2ec..b57b6625cd 100644 --- a/libs/ui/kis_custom_pattern.cc +++ b/libs/ui/kis_custom_pattern.cc @@ -1,193 +1,189 @@ /* * Copyright (c) 2006 Bart Coppens * * 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_custom_pattern.h" #include #include #include #include #include #include #include #include #include #include "KisDocument.h" #include "KisViewManager.h" #include "kis_image.h" #include "kis_layer.h" #include "kis_paint_device.h" #include "kis_selection.h" #include "kis_painter.h" #include #include "KisResourceServerProvider.h" #include "kis_paint_layer.h" KisCustomPattern::KisCustomPattern(QWidget *parent, const char* name, const QString& caption, KisViewManager* view) : KisWdgCustomPattern(parent, name), m_view(view) { Q_ASSERT(m_view); setWindowTitle(caption); m_pattern = 0; preview->setScaledContents(true); KoResourceServer* rServer = KoResourceServerProvider::instance()->patternServer(); m_rServerAdapter = QSharedPointer(new KoResourceServerAdapter(rServer)); connect(addButton, SIGNAL(pressed()), this, SLOT(slotAddPredefined())); connect(patternButton, SIGNAL(pressed()), this, SLOT(slotUsePattern())); connect(updateButton, SIGNAL(pressed()), this, SLOT(slotUpdateCurrentPattern())); connect(cmbSource, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdateCurrentPattern())); } KisCustomPattern::~KisCustomPattern() { - delete m_pattern; + m_pattern.clear(); } void KisCustomPattern::slotUpdateCurrentPattern() { - delete m_pattern; - m_pattern = 0; + m_pattern.clear(); if (m_view && m_view->image()) { createPattern(); if (m_pattern) { const qint32 maxSize = 150; if ((m_pattern->width() > maxSize) || (m_pattern->height() > maxSize)) { float aspectRatio = (float)m_pattern->width() / m_pattern->height(); qint32 scaledWidth, scaledHeight; if (m_pattern->width() > m_pattern->height()) { scaledWidth = maxSize; scaledHeight = maxSize / aspectRatio; } else { scaledWidth = maxSize * aspectRatio; scaledHeight = maxSize; } if (scaledWidth == 0) scaledWidth++; if (scaledHeight == 0) scaledHeight++; QPixmap scaledPixmap = QPixmap::fromImage(m_pattern->pattern()); preview->setPixmap(scaledPixmap.scaled(scaledWidth, scaledHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation)); } else { preview->setPixmap(QPixmap::fromImage(m_pattern->pattern())); } } } } void KisCustomPattern::slotAddPredefined() { if (!m_pattern) return; // Save in the directory that is likely to be: ~/.kde/share/apps/krita/patterns // a unique file with this pattern name QString dir = KoResourceServerProvider::instance()->patternServer()->saveLocation(); QString extension; QString tempFileName; { QTemporaryFile file(dir + QLatin1String("/krita_XXXXXX") + QLatin1String(".pat") ); file.setAutoRemove(false); file.open(); tempFileName = file.fileName(); } // Save it to that file m_pattern->setFilename(tempFileName); // Add it to the pattern server, so that it automatically gets to the mediators, and // so to the other pattern choosers can pick it up, if they want to m_rServerAdapter->addResource(m_pattern->clone()); } void KisCustomPattern::slotUsePattern() { if (!m_pattern) return; - KoPattern* copy = m_pattern->clone(); - - Q_CHECK_PTR(copy); - + KoPatternSP copy = m_pattern->clone(); emit(activatedResource(copy)); } void KisCustomPattern::createPattern() { if (!m_view) return; KisPaintDeviceSP dev; KisPaintDeviceSP cache; QString name; KisImageWSP image = m_view->image(); if (!image) return; QRect rc = image->bounds(); if (cmbSource->currentIndex() == 0) { dev = m_view->activeNode()->projection(); name = m_view->activeNode()->name(); QRect rc2 = dev->exactBounds(); rc = rc.intersected(rc2); } else { image->lock(); dev = image->projection(); image->unlock(); name = image->objectName(); } if (!dev) return; if(m_view->selection()) { KisSelectionSP selection = m_view->selection(); QRect selectionRect = selection->selectedExactRect(); cache = dev->createCompositionSourceDevice(); KisPainter gc(cache); gc.setSelection(selection); gc.bitBlt(selectionRect.topLeft(), dev, selectionRect); rc = selectionRect; } else { cache = dev; } if (!cache) return; // warn when creating large patterns QSize size = rc.size(); if (size.width() > 1000 || size.height() > 1000) { lblWarning->setText(i18n("The current image is too big to create a pattern. " - "The pattern will be scaled down.")); + "The pattern will be scaled down.")); size.scale(1000, 1000, Qt::KeepAspectRatio); } QString dir = KoResourceServerProvider::instance()->patternServer()->saveLocation(); - m_pattern = new KoPattern(cache->createThumbnail(size.width(), size.height(), rc, /*oversample*/ 1, - KoColorConversionTransformation::internalRenderingIntent(), - KoColorConversionTransformation::internalConversionFlags()), name, dir); + m_pattern = KoPatternSP(new KoPattern(cache->createThumbnail(size.width(), size.height(), rc, /*oversample*/ 1, + KoColorConversionTransformation::internalRenderingIntent(), + KoColorConversionTransformation::internalConversionFlags()), name, dir)); } diff --git a/libs/ui/kis_custom_pattern.h b/libs/ui/kis_custom_pattern.h index 76545bd91f..63efd6e62c 100644 --- a/libs/ui/kis_custom_pattern.h +++ b/libs/ui/kis_custom_pattern.h @@ -1,67 +1,68 @@ /* * Copyright (c) 2006 Bart Coppens * * 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_CUSTOM_PATTERN_H_ #define KIS_CUSTOM_PATTERN_H_ #include #include #include #include "ui_wdgcustompattern.h" -class KoPattern; -class KoResource; +#include +#include + class KisViewManager; class KisWdgCustomPattern : public QWidget, public Ui::KisWdgCustomPattern { Q_OBJECT public: KisWdgCustomPattern(QWidget *parent, const char *name) : QWidget(parent) { setObjectName(name); setupUi(this); } }; class KisCustomPattern : public KisWdgCustomPattern { Q_OBJECT public: KisCustomPattern(QWidget *parent, const char* name, const QString& caption, KisViewManager* view); ~KisCustomPattern() override; Q_SIGNALS: - void activatedResource(KoResource *); - void addPattern(KoPattern*); + void activatedResource(KoResourceSP); + void addPattern(KoPatternSP); private Q_SLOTS: void slotAddPredefined(); void slotUsePattern(); void slotUpdateCurrentPattern(); private: void createPattern(); KisViewManager* m_view; - KoPattern* m_pattern; + KoPatternSP m_pattern; QSharedPointer m_rServerAdapter; }; #endif // KIS_CUSTOM_PATTERN_H_ diff --git a/libs/ui/kis_favorite_resource_manager.cpp b/libs/ui/kis_favorite_resource_manager.cpp index bca8e0f365..b18d41bd52 100644 --- a/libs/ui/kis_favorite_resource_manager.cpp +++ b/libs/ui/kis_favorite_resource_manager.cpp @@ -1,354 +1,354 @@ /* This file is part of the KDE project Copyright 2009 Vera Lukman Copyright 2011 Sven Langkamp This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. 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 "kis_favorite_resource_manager.h" #include "kis_popup_palette.h" #include "kis_paintop_box.h" #include "KisViewManager.h" #include "KisResourceServerProvider.h" #include "kis_min_heap.h" #include "kis_config.h" #include "kis_config_notifier.h" class KisFavoriteResourceManager::ColorDataList { public: static const int MAX_RECENT_COLOR = 12; ColorDataList() { m_key = 0; } ~ColorDataList() { qDeleteAll(m_guiList); } int size() { return m_guiList.size(); } int leastUsedGuiPos() { return findPos(m_priorityList.valueAt(0)); } const KoColor& guiColor(int pos) { Q_ASSERT_X(pos < size(), "ColorDataList::guiColor", "index out of bound"); Q_ASSERT_X(pos >= 0, "ColorDataList::guiColor", "negative index"); return m_guiList.at(pos)->data; } void append(const KoColor& data) { int pos = findPos(data); if (pos > -1) updateKey(pos); else appendNew(data); } void appendNew(const KoColor& data) { if (size() >= ColorDataList::MAX_RECENT_COLOR) removeLeastUsed(); PriorityNode * node; node = new PriorityNode (); node->data = data; node->key = m_key++; m_priorityList.append(node); int pos = guiInsertPos(data); pos >= m_guiList.size() ? m_guiList.append(node) : m_guiList.insert(pos, node); node = 0; } void removeLeastUsed() { Q_ASSERT_X(size() >= 0, "ColorDataList::removeLeastUsed", "index out of bound"); if (size() <= 0) return; int pos = findPos(m_priorityList.valueAt(0)); m_guiList.removeAt(pos); m_priorityList.remove(0); } void updateKey(int guiPos) { if (m_guiList.at(guiPos)->key == m_key - 1) return; m_priorityList.changeKey(m_guiList.at(guiPos)->pos, m_key++); } /*find position of the color on the gui list*/ int findPos(const KoColor& color) { int low = 0, high = size(), mid = 0; while (low < high) { mid = (low + high) / 2; if (hsvComparison(color, m_guiList.at(mid)->data) == 0) return mid; else if (hsvComparison(color, m_guiList.at(mid)->data) < 0) high = mid; else low = mid + 1; } return -1; } private: int m_key; int guiInsertPos(const KoColor& color) { int low = 0, high = size() - 1, mid = (low + high) / 2; while (low < high) { hsvComparison(color, m_guiList[mid]->data) == -1 ? high = mid : low = mid + 1; mid = (low + high) / 2; } if (m_guiList.size() > 0) { if (hsvComparison(color, m_guiList[mid]->data) == 1) ++mid; } return mid; } /*compares c1 and c2 based on HSV. c1 < c2, returns -1 c1 = c2, returns 0 c1 > c2, returns 1 */ int hsvComparison(const KoColor& c1, const KoColor& c2) { QColor qc1 = c1.toQColor(); QColor qc2 = c2.toQColor(); if (qc1.hue() < qc2.hue()) return -1; if (qc1.hue() > qc2.hue()) return 1; // hue is the same, ok let's compare saturation if (qc1.saturation() < qc2.saturation()) return -1; if (qc1.saturation() > qc2.saturation()) return 1; // oh, also saturation is same? if (qc1.value() < qc2.value()) return -1; if (qc1.value() > qc2.value()) return 1; // user selected two similar colors return 0; } KisMinHeap m_priorityList; QList *> m_guiList; }; KisFavoriteResourceManager::KisFavoriteResourceManager(KisPaintopBox *paintopBox) : m_paintopBox(paintopBox) , m_colorList(0) , m_blockUpdates(false) , m_initialized(false) { KisConfig cfg(true); m_maxPresets = cfg.favoritePresets(); m_colorList = new ColorDataList(); connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(configChanged())); KisPaintOpPresetResourceServer * rServer = KisResourceServerProvider::instance()->paintOpPresetServer(); rServer->addObserver(this); } KisFavoriteResourceManager::~KisFavoriteResourceManager() { KisPaintOpPresetResourceServer *rServer = KisResourceServerProvider::instance()->paintOpPresetServer(); rServer->removeObserver(this); delete m_colorList; } void KisFavoriteResourceManager::unsetResourceServer() { // ... } QVector KisFavoriteResourceManager::favoritePresetList() { init(); return m_favoritePresetsList; } QList KisFavoriteResourceManager::favoritePresetImages() { init(); QList images; Q_FOREACH (KisPaintOpPresetSP preset, m_favoritePresetsList) { if (preset) { images.append(preset->image()); } } return images; } void KisFavoriteResourceManager::setCurrentTag(const QString& tagName) { m_currentTag = tagName; KisConfig(false).writeEntry("favoritePresetsTag", tagName); updateFavoritePresets(); } void KisFavoriteResourceManager::slotChangeActivePaintop(int pos) { if (pos < 0 || pos >= m_favoritePresetsList.size()) return; - KoResource* resource = const_cast(m_favoritePresetsList.at(pos).data()); + KoResourceSP resource = m_favoritePresetsList.at(pos);; m_paintopBox->resourceSelected(resource); emit hidePalettes(); } int KisFavoriteResourceManager::numFavoritePresets() { init(); return m_favoritePresetsList.size(); } //Recent Colors void KisFavoriteResourceManager::slotUpdateRecentColor(int pos) { // Do not update the key, the colour might be selected but it is not used yet. So we are not supposed // to update the colour priority when we select it. m_colorList->updateKey(pos); emit setSelectedColor(pos); emit sigSetFGColor(m_colorList->guiColor(pos)); emit hidePalettes(); } void KisFavoriteResourceManager::slotAddRecentColor(const KoColor& color) { m_colorList->append(color); int pos = m_colorList->findPos(color); emit setSelectedColor(pos); } void KisFavoriteResourceManager::slotChangeFGColorSelector(KoColor c) { emit sigChangeFGColorSelector(c); } -void KisFavoriteResourceManager::removingResource(PointerType resource) +void KisFavoriteResourceManager::removingResource(QSharedPointer resource) { if (m_blockUpdates) { return; } - if (m_favoritePresetsList.contains(resource.data())) { + if (m_favoritePresetsList.contains(resource)) { updateFavoritePresets(); } } -void KisFavoriteResourceManager::resourceAdded(PointerType /*resource*/) +void KisFavoriteResourceManager::resourceAdded(QSharedPointer /*resource*/) { if (m_blockUpdates) { return; } updateFavoritePresets(); } -void KisFavoriteResourceManager::resourceChanged(PointerType /*resource*/) +void KisFavoriteResourceManager::resourceChanged(QSharedPointer /*resource*/) { } void KisFavoriteResourceManager::setBlockUpdates(bool block) { m_blockUpdates = block; if (!block) { updateFavoritePresets(); } } void KisFavoriteResourceManager::syncTaggedResourceView() { if (m_blockUpdates) { return; } updateFavoritePresets(); } void KisFavoriteResourceManager::syncTagAddition(const QString& /*tag*/) {} void KisFavoriteResourceManager::syncTagRemoval(const QString& /*tag*/) {} int KisFavoriteResourceManager::recentColorsTotal() { return m_colorList->size(); } const KoColor& KisFavoriteResourceManager::recentColorAt(int pos) { return m_colorList->guiColor(pos); } void KisFavoriteResourceManager::slotSetBGColor(const KoColor c) { m_bgColor = c; } KoColor KisFavoriteResourceManager::bgColor() const { return m_bgColor; } bool sortPresetByName(KisPaintOpPresetSP preset1, KisPaintOpPresetSP preset2) { return preset1->name() < preset2->name(); } void KisFavoriteResourceManager::updateFavoritePresets() { m_favoritePresetsList.clear(); KisPaintOpPresetResourceServer* rServer = KisResourceServerProvider::instance()->paintOpPresetServer(); QStringList presetFilenames = rServer->searchTag(m_currentTag); for(int i = 0; i < qMin(m_maxPresets, presetFilenames.size()); i++) { KisPaintOpPresetSP pr = rServer->resourceByFilename(presetFilenames.at(i)); - m_favoritePresetsList.append(pr.data()); + m_favoritePresetsList.append(pr); std::sort(m_favoritePresetsList.begin(), m_favoritePresetsList.end(), sortPresetByName); } emit updatePalettes(); } void KisFavoriteResourceManager::configChanged() { KisConfig cfg(true); m_maxPresets = cfg.favoritePresets(); updateFavoritePresets(); } void KisFavoriteResourceManager::init() { if (!m_initialized) { m_initialized = true; KisResourceServerProvider::instance()->paintOpPresetServer(); m_currentTag = KisConfig(true).readEntry("favoritePresetsTag", "★ My Favorites"); updateFavoritePresets(); } } diff --git a/libs/ui/kis_favorite_resource_manager.h b/libs/ui/kis_favorite_resource_manager.h index aa168a6028..2af410835d 100644 --- a/libs/ui/kis_favorite_resource_manager.h +++ b/libs/ui/kis_favorite_resource_manager.h @@ -1,135 +1,136 @@ /* This file is part of the KDE project Copyright 2009 Vera Lukman This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_FAVORITE_RESOURCE_MANAGER_H #define KIS_FAVORITE_RESOURCE_MANAGER_H #include #include #include #include #include "KoResourceServerObserver.h" #include +#include class QString; class KisPaintopBox; class KisPaintOpPreset; -class KisFavoriteResourceManager : public QObject, public KoResourceServerObserver > +class KisFavoriteResourceManager : public QObject, public KoResourceServerObserver { Q_OBJECT public: KisFavoriteResourceManager(KisPaintopBox *paintopBox); ~KisFavoriteResourceManager() override; void unsetResourceServer() override; QList favoritePresetImages(); void setCurrentTag(const QString& tagName); int numFavoritePresets(); QVector favoritePresetList(); int recentColorsTotal(); const KoColor& recentColorAt(int pos); // Reimplemented from KoResourceServerObserver - void removingResource(PointerType resource) override; - void resourceAdded(PointerType resource) override; - void resourceChanged(PointerType resource) override; + void removingResource(QSharedPointer resource) override; + void resourceAdded(QSharedPointer resource) override; + void resourceChanged(QSharedPointer resource) override; void syncTaggedResourceView() override; void syncTagAddition(const QString& tag) override; void syncTagRemoval(const QString& tag) override; //BgColor; KoColor bgColor() const; /** * Set palette to block updates, paintops won't be deleted when they are deleted from server * Used when overwriting a resource */ void setBlockUpdates(bool block); Q_SIGNALS: void sigSetFGColor(const KoColor& c); void sigSetBGColor(const KoColor& c); // This is a flag to handle a bug: // If pop up palette is visible and a new colour is selected, the new colour // will be added when the user clicks on the canvas to hide the palette // In general, we want to be able to store recent colours if the pop up palette // is not visible void sigEnableChangeColor(bool b); void sigChangeFGColorSelector(const KoColor&); void setSelectedColor(int); void updatePalettes(); void hidePalettes(); public Q_SLOTS: void slotChangeActivePaintop(int); /*update the priority of a colour in m_colorList, used only by m_popupPalette*/ void slotUpdateRecentColor(int); /*add a colour to m_colorList, used by KisCanvasResourceProvider*/ void slotAddRecentColor(const KoColor&); void slotChangeFGColorSelector(KoColor c); void slotSetBGColor(const KoColor c); private Q_SLOTS: void updateFavoritePresets(); void configChanged(); private: // Loads the favorite preset list for the first time void init(); KisPaintopBox *m_paintopBox; QVector m_favoritePresetsList; class ColorDataList; ColorDataList *m_colorList; bool m_blockUpdates; void saveFavoritePresets(); KoColor m_bgColor; QString m_currentTag; bool m_initialized; int m_maxPresets; }; #endif diff --git a/libs/ui/kis_paintop_box.cc b/libs/ui/kis_paintop_box.cc index f580a74490..793b2f607c 100644 --- a/libs/ui/kis_paintop_box.cc +++ b/libs/ui/kis_paintop_box.cc @@ -1,1346 +1,1349 @@ /* * kis_paintop_box.cc - part of KImageShop/Krayon/Krita * * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) * Copyright (c) 2009-2011 Sven Langkamp (sven.langkamp@gmail.com) * Copyright (c) 2010 Lukáš Tvrdý * Copyright (C) 2011 Silvio Heinrich * Copyright (C) 2011 Srikanth Tiyyagura * Copyright (c) 2014 Mohit Goyal * * 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_paintop_box.h" #include #include #include #include #include #include #include #include #include +#include #include #include #include - #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include "kis_canvas2.h" #include "kis_node_manager.h" #include "KisViewManager.h" #include "kis_canvas_resource_provider.h" #include "KisResourceServerProvider.h" #include "kis_favorite_resource_manager.h" #include "kis_config.h" #include "kis_popup_button.h" #include "widgets/kis_iconwidget.h" #include "widgets/kis_tool_options_popup.h" #include "widgets/kis_paintop_presets_popup.h" #include "widgets/kis_paintop_presets_chooser_popup.h" #include "widgets/kis_workspace_chooser.h" #include "widgets/kis_paintop_list_widget.h" #include "widgets/kis_slider_spin_box.h" #include "widgets/kis_cmb_composite.h" #include "widgets/kis_widget_chooser.h" #include "tool/kis_tool.h" #include "kis_signals_blocker.h" #include "kis_action_manager.h" #include "kis_highlighted_button.h" -typedef KoResourceServerSimpleConstruction > KisPaintOpPresetResourceServer; -typedef KoResourceServerAdapter > KisPaintOpPresetResourceServerAdapter; - KisPaintopBox::KisPaintopBox(KisViewManager *view, QWidget *parent, const char *name) : QWidget(parent) , m_resourceProvider(view->resourceProvider()) , m_optionWidget(0) , m_toolOptionsPopupButton(0) , m_brushEditorPopupButton(0) , m_presetSelectorPopupButton(0) , m_toolOptionsPopup(0) , m_viewManager(view) , m_previousNode(0) , m_currTabletToolID(KoInputDevice::invalid()) , m_presetsEnabled(true) , m_blockUpdate(false) , m_dirtyPresetsEnabled(false) , m_eraserBrushSizeEnabled(false) , m_eraserBrushOpacityEnabled(false) { Q_ASSERT(view != 0); setObjectName(name); KisConfig cfg(true); m_dirtyPresetsEnabled = cfg.useDirtyPresets(); m_eraserBrushSizeEnabled = cfg.useEraserBrushSize(); m_eraserBrushOpacityEnabled = cfg.useEraserBrushOpacity(); KAcceleratorManager::setNoAccel(this); setWindowTitle(i18n("Painter's Toolchest")); m_favoriteResourceManager = new KisFavoriteResourceManager(this); KConfigGroup grp = KSharedConfig::openConfig()->group("krita").group("Toolbar BrushesAndStuff"); int iconsize = grp.readEntry("IconSize", 32); if (!cfg.toolOptionsInDocker()) { m_toolOptionsPopupButton = new KisPopupButton(this); m_toolOptionsPopupButton->setIcon(KisIconUtils::loadIcon("configure")); m_toolOptionsPopupButton->setToolTip(i18n("Tool Settings")); m_toolOptionsPopupButton->setFixedSize(iconsize, iconsize); } m_brushEditorPopupButton = new KisIconWidget(this); m_brushEditorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_02")); m_brushEditorPopupButton->setToolTip(i18n("Edit brush settings")); m_brushEditorPopupButton->setFixedSize(iconsize, iconsize); m_presetSelectorPopupButton = new KisPopupButton(this); m_presetSelectorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_01")); m_presetSelectorPopupButton->setToolTip(i18n("Choose brush preset")); m_presetSelectorPopupButton->setFixedSize(iconsize, iconsize); m_eraseModeButton = new KisHighlightedToolButton(this); m_eraseModeButton->setFixedSize(iconsize, iconsize); m_eraseModeButton->setCheckable(true); m_eraseAction = m_viewManager->actionManager()->createAction("erase_action"); m_eraseModeButton->setDefaultAction(m_eraseAction); m_reloadButton = new QToolButton(this); m_reloadButton->setFixedSize(iconsize, iconsize); m_reloadAction = m_viewManager->actionManager()->createAction("reload_preset_action"); m_reloadButton->setDefaultAction(m_reloadAction); m_alphaLockButton = new KisHighlightedToolButton(this); m_alphaLockButton->setFixedSize(iconsize, iconsize); m_alphaLockButton->setCheckable(true); KisAction* alphaLockAction = m_viewManager->actionManager()->createAction("preserve_alpha"); m_alphaLockButton->setDefaultAction(alphaLockAction); // horizontal and vertical mirror toolbar buttons // mirror tool options for the X Mirror QMenu *toolbarMenuXMirror = new QMenu(); hideCanvasDecorationsX = m_viewManager->actionManager()->createAction("mirrorX-hideDecorations"); toolbarMenuXMirror->addAction(hideCanvasDecorationsX); lockActionX = m_viewManager->actionManager()->createAction("mirrorX-lock"); toolbarMenuXMirror->addAction(lockActionX); moveToCenterActionX = m_viewManager->actionManager()->createAction("mirrorX-moveToCenter"); toolbarMenuXMirror->addAction(moveToCenterActionX); // mirror tool options for the Y Mirror QMenu *toolbarMenuYMirror = new QMenu(); hideCanvasDecorationsY = m_viewManager->actionManager()->createAction("mirrorY-hideDecorations"); toolbarMenuYMirror->addAction(hideCanvasDecorationsY); lockActionY = m_viewManager->actionManager()->createAction("mirrorY-lock"); toolbarMenuYMirror->addAction(lockActionY); moveToCenterActionY = m_viewManager->actionManager()->createAction("mirrorY-moveToCenter"); toolbarMenuYMirror->addAction(moveToCenterActionY); // create horizontal and vertical mirror buttons m_hMirrorButton = new KisHighlightedToolButton(this); int menuPadding = 10; m_hMirrorButton->setFixedSize(iconsize + menuPadding, iconsize); m_hMirrorButton->setCheckable(true); m_hMirrorAction = m_viewManager->actionManager()->createAction("hmirror_action"); m_hMirrorButton->setDefaultAction(m_hMirrorAction); m_hMirrorButton->setMenu(toolbarMenuXMirror); m_hMirrorButton->setPopupMode(QToolButton::MenuButtonPopup); m_vMirrorButton = new KisHighlightedToolButton(this); m_vMirrorButton->setFixedSize(iconsize + menuPadding, iconsize); m_vMirrorButton->setCheckable(true); m_vMirrorAction = m_viewManager->actionManager()->createAction("vmirror_action"); m_vMirrorButton->setDefaultAction(m_vMirrorAction); m_vMirrorButton->setMenu(toolbarMenuYMirror); m_vMirrorButton->setPopupMode(QToolButton::MenuButtonPopup); // add connections for horizontal and mirrror buttons connect(lockActionX, SIGNAL(toggled(bool)), this, SLOT(slotLockXMirrorToggle(bool))); connect(lockActionY, SIGNAL(toggled(bool)), this, SLOT(slotLockYMirrorToggle(bool))); connect(moveToCenterActionX, SIGNAL(triggered(bool)), this, SLOT(slotMoveToCenterMirrorX())); connect(moveToCenterActionY, SIGNAL(triggered(bool)), this, SLOT(slotMoveToCenterMirrorY())); connect(hideCanvasDecorationsX, SIGNAL(toggled(bool)), this, SLOT(slotHideDecorationMirrorX(bool))); connect(hideCanvasDecorationsY, SIGNAL(toggled(bool)), this, SLOT(slotHideDecorationMirrorY(bool))); const bool sliderLabels = cfg.sliderLabels(); int sliderWidth; if (sliderLabels) { sliderWidth = 150 * logicalDpiX() / 96; } else { sliderWidth = 120 * logicalDpiX() / 96; } for (int i = 0; i < 3; ++i) { m_sliderChooser[i] = new KisWidgetChooser(i + 1); KisDoubleSliderSpinBox* slOpacity; KisDoubleSliderSpinBox* slFlow; KisDoubleSliderSpinBox* slSize; if (sliderLabels) { slOpacity = m_sliderChooser[i]->addWidget("opacity"); slFlow = m_sliderChooser[i]->addWidget("flow"); slSize = m_sliderChooser[i]->addWidget("size"); slOpacity->setPrefix(QString("%1 ").arg(i18n("Opacity:"))); slFlow->setPrefix(QString("%1 ").arg(i18n("Flow:"))); slSize->setPrefix(QString("%1 ").arg(i18n("Size:"))); } else { slOpacity = m_sliderChooser[i]->addWidget("opacity", i18n("Opacity:")); slFlow = m_sliderChooser[i]->addWidget("flow", i18n("Flow:")); slSize = m_sliderChooser[i]->addWidget("size", i18n("Size:")); } slOpacity->setRange(0, 100, 0); slOpacity->setValue(100); slOpacity->setSingleStep(5); slOpacity->setSuffix("%"); slOpacity->setMinimumWidth(qMax(sliderWidth, slOpacity->sizeHint().width())); slOpacity->setFixedHeight(iconsize); slOpacity->setBlockUpdateSignalOnDrag(true); slFlow->setRange(0, 100, 0); slFlow->setValue(100); slFlow->setSingleStep(5); slFlow->setSuffix("%"); slFlow->setMinimumWidth(qMax(sliderWidth, slFlow->sizeHint().width())); slFlow->setFixedHeight(iconsize); slFlow->setBlockUpdateSignalOnDrag(true); slSize->setRange(0, cfg.readEntry("maximumBrushSize", 1000), 2); slSize->setValue(100); slSize->setSingleStep(1); slSize->setExponentRatio(3.0); slSize->setSuffix(i18n(" px")); slSize->setMinimumWidth(qMax(sliderWidth, slSize->sizeHint().width())); slSize->setFixedHeight(iconsize); slSize->setBlockUpdateSignalOnDrag(true); m_sliderChooser[i]->chooseWidget(cfg.toolbarSlider(i + 1)); } m_cmbCompositeOp = new KisCompositeOpComboBox(); m_cmbCompositeOp->setFixedHeight(iconsize); Q_FOREACH (KisAction * a, m_cmbCompositeOp->blendmodeActions()) { m_viewManager->actionManager()->addAction(a->text(), a); } m_workspaceWidget = new KisPopupButton(this); m_workspaceWidget->setIcon(KisIconUtils::loadIcon("view-choose")); m_workspaceWidget->setToolTip(i18n("Choose workspace")); m_workspaceWidget->setFixedSize(iconsize, iconsize); m_workspaceWidget->setPopupWidget(new KisWorkspaceChooser(view)); QHBoxLayout* baseLayout = new QHBoxLayout(this); m_paintopWidget = new QWidget(this); baseLayout->addWidget(m_paintopWidget); baseLayout->setSpacing(4); baseLayout->setContentsMargins(0, 0, 0, 0); m_layout = new QHBoxLayout(m_paintopWidget); if (!cfg.toolOptionsInDocker()) { m_layout->addWidget(m_toolOptionsPopupButton); } m_layout->addWidget(m_brushEditorPopupButton); m_layout->addWidget(m_presetSelectorPopupButton); m_layout->setSpacing(4); m_layout->setContentsMargins(0, 0, 0, 0); QWidget* compositeActions = new QWidget(this); QHBoxLayout* compositeLayout = new QHBoxLayout(compositeActions); compositeLayout->addWidget(m_cmbCompositeOp); compositeLayout->addWidget(m_eraseModeButton); compositeLayout->addWidget(m_alphaLockButton); compositeLayout->setSpacing(4); compositeLayout->setContentsMargins(0, 0, 0, 0); compositeLayout->addWidget(m_reloadButton); QWidgetAction * action; action = new QWidgetAction(this); view->actionCollection()->addAction("composite_actions", action); action->setText(i18n("Brush composite")); action->setDefaultWidget(compositeActions); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("brushslider1", action); view->actionCollection()->addAction("brushslider1", action); action->setDefaultWidget(m_sliderChooser[0]); connect(action, SIGNAL(triggered()), m_sliderChooser[0], SLOT(showPopupWidget())); connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[0], SLOT(updateThemedIcons())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("brushslider2", action); view->actionCollection()->addAction("brushslider2", action); action->setDefaultWidget(m_sliderChooser[1]); connect(action, SIGNAL(triggered()), m_sliderChooser[1], SLOT(showPopupWidget())); connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[1], SLOT(updateThemedIcons())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("brushslider3", action); view->actionCollection()->addAction("brushslider3", action); action->setDefaultWidget(m_sliderChooser[2]); connect(action, SIGNAL(triggered()), m_sliderChooser[2], SLOT(showPopupWidget())); connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_sliderChooser[2], SLOT(updateThemedIcons())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("next_favorite_preset", action); view->actionCollection()->addAction("next_favorite_preset", action); connect(action, SIGNAL(triggered()), this, SLOT(slotNextFavoritePreset())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("previous_favorite_preset", action); view->actionCollection()->addAction("previous_favorite_preset", action); connect(action, SIGNAL(triggered()), this, SLOT(slotPreviousFavoritePreset())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("previous_preset", action); view->actionCollection()->addAction("previous_preset", action); connect(action, SIGNAL(triggered()), this, SLOT(slotSwitchToPreviousPreset())); if (!cfg.toolOptionsInDocker()) { action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("show_tool_options", action); view->actionCollection()->addAction("show_tool_options", action); connect(action, SIGNAL(triggered()), m_toolOptionsPopupButton, SLOT(showPopupWidget())); } action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("show_brush_editor", action); view->actionCollection()->addAction("show_brush_editor", action); connect(action, SIGNAL(triggered()), m_brushEditorPopupButton, SLOT(showPopupWidget())); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("show_brush_presets", action); view->actionCollection()->addAction("show_brush_presets", action); connect(action, SIGNAL(triggered()), m_presetSelectorPopupButton, SLOT(showPopupWidget())); QWidget* mirrorActions = new QWidget(this); QHBoxLayout* mirrorLayout = new QHBoxLayout(mirrorActions); mirrorLayout->addWidget(m_hMirrorButton); mirrorLayout->addWidget(m_vMirrorButton); mirrorLayout->setSpacing(4); mirrorLayout->setContentsMargins(0, 0, 0, 0); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("mirror_actions", action); action->setDefaultWidget(mirrorActions); view->actionCollection()->addAction("mirror_actions", action); action = new QWidgetAction(this); KisActionRegistry::instance()->propertizeAction("workspaces", action); view->actionCollection()->addAction("workspaces", action); action->setDefaultWidget(m_workspaceWidget); if (!cfg.toolOptionsInDocker()) { m_toolOptionsPopup = new KisToolOptionsPopup(); m_toolOptionsPopupButton->setPopupWidget(m_toolOptionsPopup); m_toolOptionsPopup->switchDetached(false); } m_savePresetWidget = new KisPresetSaveWidget(this); m_presetsPopup = new KisPaintOpPresetsPopup(m_resourceProvider, m_favoriteResourceManager, m_savePresetWidget); m_brushEditorPopupButton->setPopupWidget(m_presetsPopup); m_presetsPopup->parentWidget()->setWindowTitle(i18n("Brush Editor")); connect(m_presetsPopup, SIGNAL(brushEditorShown()), SLOT(slotUpdateOptionsWidgetPopup())); connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), m_presetsPopup, SLOT(updateThemedIcons())); m_presetsChooserPopup = new KisPaintOpPresetsChooserPopup(); m_presetsChooserPopup->setMinimumHeight(550); m_presetsChooserPopup->setMinimumWidth(450); m_presetSelectorPopupButton->setPopupWidget(m_presetsChooserPopup); m_currCompositeOpID = KoCompositeOpRegistry::instance().getDefaultCompositeOp().id(); slotNodeChanged(view->activeNode()); // Get all the paintops QList keys = KisPaintOpRegistry::instance()->keys(); QList factoryList; Q_FOREACH (const QString & paintopId, keys) { factoryList.append(KisPaintOpRegistry::instance()->get(paintopId)); } m_presetsPopup->setPaintOpList(factoryList); connect(m_presetsPopup , SIGNAL(paintopActivated(QString)) , SLOT(slotSetPaintop(QString))); connect(m_presetsPopup , SIGNAL(defaultPresetClicked()) , SLOT(slotSetupDefaultPreset())); - connect(m_presetsPopup , SIGNAL(signalResourceSelected(KoResource*)), SLOT(resourceSelected(KoResource*))); + connect(m_presetsPopup , SIGNAL(signalResourceSelected(KoResourceSP )), SLOT(resourceSelected(KoResourceSP ))); connect(m_presetsPopup , SIGNAL(reloadPresetClicked()) , SLOT(slotReloadPreset())); connect(m_presetsPopup , SIGNAL(dirtyPresetToggled(bool)) , SLOT(slotDirtyPresetToggled(bool))); connect(m_presetsPopup , SIGNAL(eraserBrushSizeToggled(bool)) , SLOT(slotEraserBrushSizeToggled(bool))); connect(m_presetsPopup , SIGNAL(eraserBrushOpacityToggled(bool)) , SLOT(slotEraserBrushOpacityToggled(bool))); connect(m_presetsPopup, SIGNAL(createPresetFromScratch(QString)), this, SLOT(slotCreatePresetFromScratch(QString))); - connect(m_presetsChooserPopup, SIGNAL(resourceSelected(KoResource*)) , SLOT(resourceSelected(KoResource*))); - connect(m_presetsChooserPopup, SIGNAL(resourceClicked(KoResource*)) , SLOT(resourceSelected(KoResource*))); + connect(m_presetsChooserPopup, SIGNAL(resourceSelected(KoResourceSP )) , SLOT(resourceSelected(KoResourceSP ))); + connect(m_presetsChooserPopup, SIGNAL(resourceClicked(KoResourceSP )) , SLOT(resourceSelected(KoResourceSP ))); connect(m_resourceProvider , SIGNAL(sigNodeChanged(KisNodeSP)) , SLOT(slotNodeChanged(KisNodeSP))); connect(m_cmbCompositeOp , SIGNAL(currentIndexChanged(int)) , SLOT(slotSetCompositeMode(int))); connect(m_eraseAction , SIGNAL(toggled(bool)) , SLOT(slotToggleEraseMode(bool))); connect(alphaLockAction , SIGNAL(toggled(bool)) , SLOT(slotToggleAlphaLockMode(bool))); m_disablePressureAction = m_viewManager->actionManager()->createAction("disable_pressure"); connect(m_disablePressureAction , SIGNAL(toggled(bool)) , SLOT(slotDisablePressureMode(bool))); m_disablePressureAction->setChecked(true); connect(m_hMirrorAction , SIGNAL(toggled(bool)) , SLOT(slotHorizontalMirrorChanged(bool))); connect(m_vMirrorAction , SIGNAL(toggled(bool)) , SLOT(slotVerticalMirrorChanged(bool))); connect(m_reloadAction , SIGNAL(triggered()) , SLOT(slotReloadPreset())); connect(m_sliderChooser[0]->getWidget("opacity"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed())); connect(m_sliderChooser[0]->getWidget("flow") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed())); connect(m_sliderChooser[0]->getWidget("size") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider1Changed())); connect(m_sliderChooser[1]->getWidget("opacity"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed())); connect(m_sliderChooser[1]->getWidget("flow") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed())); connect(m_sliderChooser[1]->getWidget("size") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider2Changed())); connect(m_sliderChooser[2]->getWidget("opacity"), SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed())); connect(m_sliderChooser[2]->getWidget("flow") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed())); connect(m_sliderChooser[2]->getWidget("size") , SIGNAL(valueChanged(qreal)), SLOT(slotSlider3Changed())); //Needed to connect canvas to favorite resource manager connect(m_viewManager->resourceProvider(), SIGNAL(sigFGColorChanged(KoColor)), SLOT(slotUnsetEraseMode())); connect(m_resourceProvider, SIGNAL(sigFGColorUsed(KoColor)), m_favoriteResourceManager, SLOT(slotAddRecentColor(KoColor))); connect(m_resourceProvider, SIGNAL(sigFGColorChanged(KoColor)), m_favoriteResourceManager, SLOT(slotChangeFGColorSelector(KoColor))); connect(m_resourceProvider, SIGNAL(sigBGColorChanged(KoColor)), m_favoriteResourceManager, SLOT(slotSetBGColor(KoColor))); // cold initialization m_favoriteResourceManager->slotChangeFGColorSelector(m_resourceProvider->fgColor()); m_favoriteResourceManager->slotSetBGColor(m_resourceProvider->bgColor()); connect(m_favoriteResourceManager, SIGNAL(sigSetFGColor(KoColor)), m_resourceProvider, SLOT(slotSetFGColor(KoColor))); connect(m_favoriteResourceManager, SIGNAL(sigSetBGColor(KoColor)), m_resourceProvider, SLOT(slotSetBGColor(KoColor))); connect(m_favoriteResourceManager, SIGNAL(sigEnableChangeColor(bool)), m_resourceProvider, SLOT(slotResetEnableFGChange(bool))); connect(view->mainWindow(), SIGNAL(themeChanged()), this, SLOT(slotUpdateSelectionIcon())); connect(m_resourceProvider->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)), this, SLOT(slotCanvasResourceChanged(int,QVariant))); slotInputDeviceChanged(KoToolManager::instance()->currentInputDevice()); KisPaintOpPresetResourceServer *rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); m_eraserName = "eraser_circle"; m_defaultPresetName = "basic_tip_default"; bool foundEraser = false; bool foundTip = false; - for (int i=0; iresourceCount(); i++) { - KisPaintOpPresetSP resource = rserver->resources().at(i); + for (int i = 0; i < rserver->resourceCount(); i++) { + + KisPaintOpPresetSP resource = rserver->resources()[i]; + if (resource->name().toLower().contains("eraser_circle")) { m_eraserName = resource->name(); foundEraser = true; - } else if (foundEraser == false && (resource->name().toLower().contains("eraser") || + } + else if (foundEraser == false && (resource->name().toLower().contains("eraser") || resource->filename().toLower().contains("eraser"))) { m_eraserName = resource->name(); foundEraser = true; } + if (resource->name().toLower().contains("basic_tip_default")) { m_defaultPresetName = resource->name(); foundTip = true; - } else if (foundTip == false && (resource->name().toLower().contains("default") || + } + else if (foundTip == false && (resource->name().toLower().contains("default") || resource->filename().toLower().contains("default"))) { m_defaultPresetName = resource->name(); foundTip = true; } } } KisPaintopBox::~KisPaintopBox() { KisConfig cfg(false); QMapIterator iter(m_tabletToolMap); while (iter.hasNext()) { iter.next(); //qDebug() << "Writing last used preset for" << iter.key().pointer << iter.key().uniqueID << iter.value().preset->name(); if ((iter.key().pointer) == QTabletEvent::Eraser) { cfg.writeEntry(QString("LastEraser_%1").arg(iter.key().uniqueID) , iter.value().preset->name()); } else { cfg.writeEntry(QString("LastPreset_%1").arg(iter.key().uniqueID) , iter.value().preset->name()); } } // Do not delete the widget, since it is global to the application, not owned by the view m_presetsPopup->setPaintOpSettingsWidget(0); qDeleteAll(m_paintopOptionWidgets); delete m_favoriteResourceManager; for (int i = 0; i < 3; ++i) { delete m_sliderChooser[i]; } } -void KisPaintopBox::restoreResource(KoResource* resource) +void KisPaintopBox::restoreResource(KoResourceSP resource) { - KisPaintOpPreset* preset = dynamic_cast(resource); + KisPaintOpPresetSP preset = resource.dynamicCast(); if (preset) { setCurrentPaintop(preset); m_presetsPopup->setPresetImage(preset->image()); m_presetsPopup->resourceSelected(resource); } } void KisPaintopBox::newOptionWidgets(const QList > &optionWidgetList) { if (m_toolOptionsPopup) { m_toolOptionsPopup->newOptionWidgets(optionWidgetList); } } -void KisPaintopBox::resourceSelected(KoResource* resource) +void KisPaintopBox::resourceSelected(KoResourceSP resource) { m_presetsPopup->setCreatingBrushFromScratch(false); // show normal UI elements when we are not creating - KisPaintOpPreset* preset = dynamic_cast(resource); + KisPaintOpPresetSP preset = resource.dynamicCast(); if (preset && preset != m_resourceProvider->currentPreset()) { if (!preset->settings()->isLoadable()) return; if (!m_dirtyPresetsEnabled) { KisSignalsBlocker blocker(m_optionWidget); if (!preset->load()) { warnKrita << "failed to load the preset."; } } //qDebug() << "resourceSelected" << resource->name(); setCurrentPaintop(preset); m_presetsPopup->setPresetImage(preset->image()); m_presetsPopup->resourceSelected(resource); } } void KisPaintopBox::setCurrentPaintop(const KoID& paintop) { KisPaintOpPresetSP preset = activePreset(paintop); Q_ASSERT(preset && preset->settings()); //qDebug() << "setCurrentPaintop();" << paintop << preset; setCurrentPaintop(preset); } void KisPaintopBox::setCurrentPaintop(KisPaintOpPresetSP preset) { //qDebug() << "setCurrentPaintop(); " << preset->name(); if (preset == m_resourceProvider->currentPreset()) { if (preset == m_tabletToolMap[m_currTabletToolID].preset) { return; } } Q_ASSERT(preset); const KoID& paintop = preset->paintOp(); m_presetConnections.clear(); if (m_resourceProvider->currentPreset()) { m_resourceProvider->setPreviousPaintOpPreset(m_resourceProvider->currentPreset()); if (m_optionWidget) { m_optionWidget->hide(); } } if (!m_paintopOptionWidgets.contains(paintop)) m_paintopOptionWidgets[paintop] = KisPaintOpRegistry::instance()->get(paintop.id())->createConfigWidget(this); m_optionWidget = m_paintopOptionWidgets[paintop]; KisSignalsBlocker b(m_optionWidget); preset->setOptionsWidget(m_optionWidget); m_optionWidget->setImage(m_viewManager->image()); m_optionWidget->setNode(m_viewManager->activeNode()); m_presetsPopup->setPaintOpSettingsWidget(m_optionWidget); m_resourceProvider->setPaintOpPreset(preset); Q_ASSERT(m_optionWidget && m_presetSelectorPopupButton); m_presetConnections.addConnection(m_optionWidget, SIGNAL(sigConfigurationUpdated()), this, SLOT(slotGuiChangedCurrentPreset())); m_presetConnections.addConnection(m_optionWidget, SIGNAL(sigSaveLockedConfig(KisPropertiesConfigurationSP)), this, SLOT(slotSaveLockedOptionToPreset(KisPropertiesConfigurationSP))); m_presetConnections.addConnection(m_optionWidget, SIGNAL(sigDropLockedConfig(KisPropertiesConfigurationSP)), this, SLOT(slotDropLockedOption(KisPropertiesConfigurationSP))); // load the current brush engine icon for the brush editor toolbar button - m_brushEditorPopupButton->slotSetItem(preset.data()); + m_brushEditorPopupButton->slotSetItem(preset); m_presetsPopup->setCurrentPaintOpId(paintop.id()); ////qDebug() << "\tsetting the new preset for" << m_currTabletToolID.uniqueID << "to" << preset->name(); m_paintOpPresetMap[m_resourceProvider->currentPreset()->paintOp()] = preset; m_tabletToolMap[m_currTabletToolID].preset = preset; m_tabletToolMap[m_currTabletToolID].paintOpID = preset->paintOp(); if (m_presetsPopup->currentPaintOpId() != paintop.id()) { // Must change the paintop as the current one is not supported // by the new colorspace. dbgKrita << "current paintop " << paintop.name() << " was not set, not supported by colorspace"; } } void KisPaintopBox::slotUpdateOptionsWidgetPopup() { KisPaintOpPresetSP preset = m_resourceProvider->currentPreset(); KIS_SAFE_ASSERT_RECOVER_RETURN(preset); KIS_SAFE_ASSERT_RECOVER_RETURN(m_optionWidget); m_optionWidget->setConfigurationSafe(preset->settings()); - m_presetsPopup->resourceSelected(preset.data()); + m_presetsPopup->resourceSelected(preset); m_presetsPopup->updateViewSettings(); // the m_viewManager->image() is set earlier, but the reference will be missing when the stamp button is pressed // need to later do some research on how and when we should be using weak shared pointers (WSP) that creates this situation m_optionWidget->setImage(m_viewManager->image()); } KisPaintOpPresetSP KisPaintopBox::defaultPreset(const KoID& paintOp) { QString defaultName = paintOp.id() + ".kpp"; QString path = KoResourcePaths::findResource("kis_defaultpresets", defaultName); - KisPaintOpPresetSP preset = new KisPaintOpPreset(path); + KisPaintOpPresetSP preset(new KisPaintOpPreset(path)); if (!preset->load()) { preset = KisPaintOpRegistry::instance()->defaultPreset(paintOp); } Q_ASSERT(preset); Q_ASSERT(preset->valid()); return preset; } KisPaintOpPresetSP KisPaintopBox::activePreset(const KoID& paintOp) { if (m_paintOpPresetMap[paintOp] == 0) { m_paintOpPresetMap[paintOp] = defaultPreset(paintOp); } return m_paintOpPresetMap[paintOp]; } void KisPaintopBox::updateCompositeOp(QString compositeOpID) { if (!m_optionWidget) return; KisSignalsBlocker blocker(m_optionWidget); KisNodeSP node = m_resourceProvider->currentNode(); if (node && node->paintDevice()) { if (!node->paintDevice()->colorSpace()->hasCompositeOp(compositeOpID)) compositeOpID = KoCompositeOpRegistry::instance().getDefaultCompositeOp().id(); { KisSignalsBlocker b1(m_cmbCompositeOp); m_cmbCompositeOp->selectCompositeOp(KoID(compositeOpID)); } if (compositeOpID != m_currCompositeOpID) { m_currCompositeOpID = compositeOpID; } if (compositeOpID == COMPOSITE_ERASE || m_resourceProvider->eraserMode()) { m_eraseModeButton->setChecked(true); } else { m_eraseModeButton->setChecked(false); } } } void KisPaintopBox::setWidgetState(int flags) { if (flags & (ENABLE_COMPOSITEOP | DISABLE_COMPOSITEOP)) { m_cmbCompositeOp->setEnabled(flags & ENABLE_COMPOSITEOP); m_eraseModeButton->setEnabled(flags & ENABLE_COMPOSITEOP); } if (flags & (ENABLE_PRESETS | DISABLE_PRESETS)) { m_presetSelectorPopupButton->setEnabled(flags & ENABLE_PRESETS); m_brushEditorPopupButton->setEnabled(flags & ENABLE_PRESETS); } for (int i = 0; i < 3; ++i) { if (flags & (ENABLE_OPACITY | DISABLE_OPACITY)) m_sliderChooser[i]->getWidget("opacity")->setEnabled(flags & ENABLE_OPACITY); if (flags & (ENABLE_FLOW | DISABLE_FLOW)) m_sliderChooser[i]->getWidget("flow")->setEnabled(flags & ENABLE_FLOW); if (flags & (ENABLE_SIZE | DISABLE_SIZE)) m_sliderChooser[i]->getWidget("size")->setEnabled(flags & ENABLE_SIZE); } } void KisPaintopBox::setSliderValue(const QString& sliderID, qreal value) { for (int i = 0; i < 3; ++i) { KisDoubleSliderSpinBox* slider = m_sliderChooser[i]->getWidget(sliderID); KisSignalsBlocker b(slider); if (sliderID == "opacity" || sliderID == "flow") { // opacity and flows UI stored at 0-100% slider->setValue(value*100); } else { slider->setValue(value); // brush size } } } void KisPaintopBox::slotSetPaintop(const QString& paintOpId) { if (KisPaintOpRegistry::instance()->get(paintOpId) != 0) { KoID id(paintOpId, KisPaintOpRegistry::instance()->get(paintOpId)->name()); //qDebug() << "slotsetpaintop" << id; setCurrentPaintop(id); } } void KisPaintopBox::slotInputDeviceChanged(const KoInputDevice& inputDevice) { TabletToolMap::iterator toolData = m_tabletToolMap.find(inputDevice); //qDebug() << "slotInputDeviceChanged()" << inputDevice.device() << inputDevice.uniqueTabletId(); m_currTabletToolID = TabletToolID(inputDevice); if (toolData == m_tabletToolMap.end()) { KisConfig cfg(true); KisPaintOpPresetResourceServer *rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); KisPaintOpPresetSP preset; if (inputDevice.pointer() == QTabletEvent::Eraser) { preset = rserver->resourceByName(cfg.readEntry(QString("LastEraser_%1").arg(inputDevice.uniqueTabletId()), m_eraserName)); } else { preset = rserver->resourceByName(cfg.readEntry(QString("LastPreset_%1").arg(inputDevice.uniqueTabletId()), m_defaultPresetName)); //if (preset) //qDebug() << "found stored preset " << preset->name() << "for" << inputDevice.uniqueTabletId(); //else //qDebug() << "no preset found for" << inputDevice.uniqueTabletId(); } if (!preset) { preset = rserver->resourceByName(m_defaultPresetName); } if (preset) { //qDebug() << "inputdevicechanged 1" << preset; setCurrentPaintop(preset); } } else { if (toolData->preset) { //qDebug() << "inputdevicechanged 2" << toolData->preset; setCurrentPaintop(toolData->preset); } else { //qDebug() << "inputdevicechanged 3" << toolData->paintOpID; setCurrentPaintop(toolData->paintOpID); } } } void KisPaintopBox::slotCreatePresetFromScratch(QString paintop) { //First try to select an available default preset for that engine. If it doesn't exist, then //manually set the engine to use a new preset. KoID id(paintop, KisPaintOpRegistry::instance()->get(paintop)->name()); KisPaintOpPresetSP preset = defaultPreset(id); slotSetPaintop(paintop); // change the paintop settings area and update the UI if (!preset) { m_presetsPopup->setCreatingBrushFromScratch(true); // disable UI elements while creating from scratch preset = m_resourceProvider->currentPreset(); } else { m_resourceProvider->setPaintOpPreset(preset); preset->setOptionsWidget(m_optionWidget); } - m_presetsPopup->resourceSelected(preset.data()); // this helps update the UI on the brush editor + m_presetsPopup->resourceSelected(preset); // this helps update the UI on the brush editor } void KisPaintopBox::slotCanvasResourceChanged(int key, const QVariant &value) { if (m_viewManager) { sender()->blockSignals(true); KisPaintOpPresetSP preset = m_viewManager->resourceProvider()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value(); if (preset && m_resourceProvider->currentPreset()->name() != preset->name()) { QString compositeOp = preset->settings()->getString("CompositeOp"); updateCompositeOp(compositeOp); - resourceSelected(preset.data()); + resourceSelected(preset); } /** * Update currently selected preset in both the popup widgets */ m_presetsChooserPopup->canvasResourceChanged(preset); m_presetsPopup->currentPresetChanged(preset); if (key == KisCanvasResourceProvider::CurrentCompositeOp) { if (m_resourceProvider->currentCompositeOp() != m_currCompositeOpID) { updateCompositeOp(m_resourceProvider->currentCompositeOp()); } } if (key == KisCanvasResourceProvider::Size) { setSliderValue("size", m_resourceProvider->size()); } if (key == KisCanvasResourceProvider::Opacity) { setSliderValue("opacity", m_resourceProvider->opacity()); } if (key == KisCanvasResourceProvider::Flow) { setSliderValue("flow", m_resourceProvider->flow()); } if (key == KisCanvasResourceProvider::EraserMode) { m_eraseAction->setChecked(value.toBool()); } if (key == KisCanvasResourceProvider::DisablePressure) { m_disablePressureAction->setChecked(value.toBool()); } sender()->blockSignals(false); } } void KisPaintopBox::slotUpdatePreset() { if (!m_resourceProvider->currentPreset()) return; // block updates of avoid some over updating of the option widget m_blockUpdate = true; setSliderValue("size", m_resourceProvider->size()); { qreal opacity = m_resourceProvider->currentPreset()->settings()->paintOpOpacity(); m_resourceProvider->setOpacity(opacity); setSliderValue("opacity", opacity); setWidgetState(ENABLE_OPACITY); } { setSliderValue("flow", m_resourceProvider->currentPreset()->settings()->paintOpFlow()); setWidgetState(ENABLE_FLOW); } { updateCompositeOp(m_resourceProvider->currentPreset()->settings()->paintOpCompositeOp()); setWidgetState(ENABLE_COMPOSITEOP); } m_blockUpdate = false; } void KisPaintopBox::slotSetupDefaultPreset() { KisPaintOpPresetSP preset = defaultPreset(m_resourceProvider->currentPreset()->paintOp()); preset->setOptionsWidget(m_optionWidget); m_resourceProvider->setPaintOpPreset(preset); // tell the brush editor that the resource has changed // so it can update everything - m_presetsPopup->resourceSelected(preset.data()); + m_presetsPopup->resourceSelected(preset); } void KisPaintopBox::slotNodeChanged(const KisNodeSP node) { if (m_previousNode.isValid() && m_previousNode->paintDevice()) disconnect(m_previousNode->paintDevice().data(), SIGNAL(colorSpaceChanged(const KoColorSpace*)), this, SLOT(slotColorSpaceChanged(const KoColorSpace*))); // Reconnect colorspace change of node if (node && node->paintDevice()) { connect(node->paintDevice().data(), SIGNAL(colorSpaceChanged(const KoColorSpace*)), this, SLOT(slotColorSpaceChanged(const KoColorSpace*))); m_resourceProvider->setCurrentCompositeOp(m_currCompositeOpID); m_previousNode = node; slotColorSpaceChanged(node->colorSpace()); } if (m_optionWidget) { m_optionWidget->setNode(node); } } void KisPaintopBox::slotColorSpaceChanged(const KoColorSpace* colorSpace) { m_cmbCompositeOp->validate(colorSpace); } void KisPaintopBox::slotToggleEraseMode(bool checked) { const bool oldEraserMode = m_resourceProvider->eraserMode(); m_resourceProvider->setEraserMode(checked); if (oldEraserMode != checked && m_eraserBrushSizeEnabled) { const qreal currentSize = m_resourceProvider->size(); KisPaintOpSettingsSP settings = m_resourceProvider->currentPreset()->settings(); // remember brush size. set the eraser size to the normal brush size if not set if (checked) { settings->setSavedBrushSize(currentSize); if (qFuzzyIsNull(settings->savedEraserSize())) { settings->setSavedEraserSize(currentSize); } } else { settings->setSavedEraserSize(currentSize); if (qFuzzyIsNull(settings->savedBrushSize())) { settings->setSavedBrushSize(currentSize); } } //update value in UI (this is the main place the value is 'stored' in memory) qreal newSize = checked ? settings->savedEraserSize() : settings->savedBrushSize(); m_resourceProvider->setSize(newSize); } if (oldEraserMode != checked && m_eraserBrushOpacityEnabled) { const qreal currentOpacity = m_resourceProvider->opacity(); KisPaintOpSettingsSP settings = m_resourceProvider->currentPreset()->settings(); // remember brush opacity. set the eraser opacity to the normal brush opacity if not set if (checked) { settings->setSavedBrushOpacity(currentOpacity); if (qFuzzyIsNull(settings->savedEraserOpacity())) { settings->setSavedEraserOpacity(currentOpacity); } } else { settings->setSavedEraserOpacity(currentOpacity); if (qFuzzyIsNull(settings->savedBrushOpacity())) { settings->setSavedBrushOpacity(currentOpacity); } } //update value in UI (this is the main place the value is 'stored' in memory) qreal newOpacity = checked ? settings->savedEraserOpacity() : settings->savedBrushOpacity(); m_resourceProvider->setOpacity(newOpacity); } } void KisPaintopBox::slotSetCompositeMode(int index) { Q_UNUSED(index); QString compositeOp = m_cmbCompositeOp->selectedCompositeOp().id(); m_resourceProvider->setCurrentCompositeOp(compositeOp); } void KisPaintopBox::slotHorizontalMirrorChanged(bool value) { m_resourceProvider->setMirrorHorizontal(value); } void KisPaintopBox::slotVerticalMirrorChanged(bool value) { m_resourceProvider->setMirrorVertical(value); } void KisPaintopBox::sliderChanged(int n) { if (!m_optionWidget) // widget will not exist if the are no documents open return; KisSignalsBlocker blocker(m_optionWidget); // flow and opacity are shown as 0-100% on the UI, but their data is actually 0-1. Convert those two values // back for further work qreal opacity = m_sliderChooser[n]->getWidget("opacity")->value()/100; qreal flow = m_sliderChooser[n]->getWidget("flow")->value()/100; qreal size = m_sliderChooser[n]->getWidget("size")->value(); setSliderValue("opacity", opacity); setSliderValue("flow" , flow); setSliderValue("size" , size); if (m_presetsEnabled) { // IMPORTANT: set the PaintOp size before setting the other properties // it won't work the other way // TODO: why?! m_resourceProvider->setSize(size); m_resourceProvider->setOpacity(opacity); m_resourceProvider->setFlow(flow); KisLockedPropertiesProxySP propertiesProxy = KisLockedPropertiesServer::instance()->createLockedPropertiesProxy(m_resourceProvider->currentPreset()->settings()); propertiesProxy->setProperty("OpacityValue", opacity); propertiesProxy->setProperty("FlowValue", flow); m_optionWidget->setConfigurationSafe(m_resourceProvider->currentPreset()->settings().data()); } else { m_resourceProvider->setOpacity(opacity); } - m_presetsPopup->resourceSelected(m_resourceProvider->currentPreset().data()); + m_presetsPopup->resourceSelected(m_resourceProvider->currentPreset()); } void KisPaintopBox::slotSlider1Changed() { sliderChanged(0); } void KisPaintopBox::slotSlider2Changed() { sliderChanged(1); } void KisPaintopBox::slotSlider3Changed() { sliderChanged(2); } void KisPaintopBox::slotToolChanged(KoCanvasController* canvas, int toolId) { Q_UNUSED(canvas); Q_UNUSED(toolId); if (!m_viewManager->canvasBase()) return; QString id = KoToolManager::instance()->activeToolId(); KisTool* tool = dynamic_cast(KoToolManager::instance()->toolById(m_viewManager->canvasBase(), id)); if (tool) { int flags = tool->flags(); if (flags & KisTool::FLAG_USES_CUSTOM_COMPOSITEOP) { setWidgetState(ENABLE_COMPOSITEOP | ENABLE_OPACITY); } else { setWidgetState(DISABLE_COMPOSITEOP | DISABLE_OPACITY); } if (flags & KisTool::FLAG_USES_CUSTOM_PRESET) { setWidgetState(ENABLE_PRESETS); slotUpdatePreset(); m_presetsEnabled = true; } else { setWidgetState(DISABLE_PRESETS); m_presetsEnabled = false; } if (flags & KisTool::FLAG_USES_CUSTOM_SIZE) { setWidgetState(ENABLE_SIZE | ENABLE_FLOW); } else { setWidgetState(DISABLE_SIZE | DISABLE_FLOW); } } else setWidgetState(DISABLE_ALL); } void KisPaintopBox::slotPreviousFavoritePreset() { if (!m_favoriteResourceManager) return; QVector presets = m_favoriteResourceManager->favoritePresetList(); for (int i=0; i < presets.size(); ++i) { if (m_resourceProvider->currentPreset() && m_resourceProvider->currentPreset()->name() == presets[i]->name()) { if (i > 0) { m_favoriteResourceManager->slotChangeActivePaintop(i - 1); } else { m_favoriteResourceManager->slotChangeActivePaintop(m_favoriteResourceManager->numFavoritePresets() - 1); } //floating message should have least 2 lines, otherwise //preset thumbnail will be too small to distinguish //(because size of image on floating message depends on amount of lines in msg) m_viewManager->showFloatingMessage( i18n("%1\nselected", m_resourceProvider->currentPreset()->name()), QIcon(QPixmap::fromImage(m_resourceProvider->currentPreset()->image()))); return; } } } void KisPaintopBox::slotNextFavoritePreset() { if (!m_favoriteResourceManager) return; QVector presets = m_favoriteResourceManager->favoritePresetList(); for(int i = 0; i < presets.size(); ++i) { if (m_resourceProvider->currentPreset()->name() == presets[i]->name()) { if (i < m_favoriteResourceManager->numFavoritePresets() - 1) { m_favoriteResourceManager->slotChangeActivePaintop(i + 1); } else { m_favoriteResourceManager->slotChangeActivePaintop(0); } m_viewManager->showFloatingMessage( i18n("%1\nselected", m_resourceProvider->currentPreset()->name()), QIcon(QPixmap::fromImage(m_resourceProvider->currentPreset()->image()))); return; } } } void KisPaintopBox::slotSwitchToPreviousPreset() { if (m_resourceProvider->previousPreset()) { //qDebug() << "slotSwitchToPreviousPreset();" << m_resourceProvider->previousPreset(); setCurrentPaintop(m_resourceProvider->previousPreset()); m_viewManager->showFloatingMessage( i18n("%1\nselected", m_resourceProvider->currentPreset()->name()), QIcon(QPixmap::fromImage(m_resourceProvider->currentPreset()->image()))); } } void KisPaintopBox::slotUnsetEraseMode() { m_eraseAction->setChecked(false); } void KisPaintopBox::slotToggleAlphaLockMode(bool checked) { if (checked) { m_alphaLockButton->actions()[0]->setIcon(KisIconUtils::loadIcon("transparency-locked")); } else { m_alphaLockButton->actions()[0]->setIcon(KisIconUtils::loadIcon("transparency-unlocked")); } m_resourceProvider->setGlobalAlphaLock(checked); } void KisPaintopBox::slotDisablePressureMode(bool checked) { if (checked) { m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure")); } else { m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure_locked")); } m_resourceProvider->setDisablePressure(checked); } void KisPaintopBox::slotReloadPreset() { KisSignalsBlocker blocker(m_optionWidget); - //Here using the name and fetching the preset from the server was the only way the load was working. Otherwise it was not loading. - KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); - KisPaintOpPresetSP preset = rserver->resourceByName(m_resourceProvider->currentPreset()->name()); + // Here using the name and fetching the preset from the server was the only way the load was working. Otherwise it was not loading. + KisPaintOpPresetResourceServer *rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); + QSharedPointer preset = rserver->resourceByName(m_resourceProvider->currentPreset()->name()); if (preset) { preset->load(); } } void KisPaintopBox::slotGuiChangedCurrentPreset() // Called only when UI is changed and not when preset is changed { KisPaintOpPresetSP preset = m_resourceProvider->currentPreset(); { /** * Here we postpone all the settings updates events until the entire writing * operation will be finished. As soon as it is finished, the updates will be * emitted happily (if there were any). */ - KisPaintOpPreset::UpdatedPostponer postponer(preset.data()); + KisPaintOpPreset::UpdatedPostponer postponer(preset); QStringList preserveProperties; preserveProperties << "lodUserAllowed"; preserveProperties << "lodSizeThreshold"; // clear all the properties before dumping the stuff into the preset, // some of the options add the values incrementally // (e.g. KisPaintOpUtils::RequiredBrushFilesListTag), therefore they // may add up if we pass the same preset multiple times preset->settings()->resetSettings(preserveProperties); m_optionWidget->writeConfigurationSafe(const_cast(preset->settings().data())); } // we should also update the preset strip to update the status of the "dirty" mark - m_presetsPopup->resourceSelected(m_resourceProvider->currentPreset().data()); + m_presetsPopup->resourceSelected(m_resourceProvider->currentPreset()); // TODO!!!!!!!! //m_presetsPopup->updateViewSettings(); } void KisPaintopBox::slotSaveLockedOptionToPreset(KisPropertiesConfigurationSP p) { QMapIterator i(p->getProperties()); while (i.hasNext()) { i.next(); m_resourceProvider->currentPreset()->settings()->setProperty(i.key(), QVariant(i.value())); if (m_resourceProvider->currentPreset()->settings()->hasProperty(i.key() + "_previous")) { m_resourceProvider->currentPreset()->settings()->removeProperty(i.key() + "_previous"); } } slotGuiChangedCurrentPreset(); } void KisPaintopBox::slotDropLockedOption(KisPropertiesConfigurationSP p) { KisSignalsBlocker blocker(m_optionWidget); KisPaintOpPresetSP preset = m_resourceProvider->currentPreset(); { - KisPaintOpPreset::DirtyStateSaver dirtySaver(preset.data()); + KisPaintOpPreset::DirtyStateSaver dirtySaver(preset); QMapIterator i(p->getProperties()); while (i.hasNext()) { i.next(); if (preset->settings()->hasProperty(i.key() + "_previous")) { preset->settings()->setProperty(i.key(), preset->settings()->getProperty(i.key() + "_previous")); preset->settings()->removeProperty(i.key() + "_previous"); } } } //slotUpdatePreset(); } void KisPaintopBox::slotDirtyPresetToggled(bool value) { if (!value) { slotReloadPreset(); - m_presetsPopup->resourceSelected(m_resourceProvider->currentPreset().data()); + m_presetsPopup->resourceSelected(m_resourceProvider->currentPreset()); m_presetsPopup->updateViewSettings(); } m_dirtyPresetsEnabled = value; KisConfig cfg(false); cfg.setUseDirtyPresets(m_dirtyPresetsEnabled); } void KisPaintopBox::slotEraserBrushSizeToggled(bool value) { m_eraserBrushSizeEnabled = value; KisConfig cfg(false); cfg.setUseEraserBrushSize(m_eraserBrushSizeEnabled); } void KisPaintopBox::slotEraserBrushOpacityToggled(bool value) { m_eraserBrushOpacityEnabled = value; KisConfig cfg(false); cfg.setUseEraserBrushOpacity(m_eraserBrushOpacityEnabled); } void KisPaintopBox::slotUpdateSelectionIcon() { m_hMirrorAction->setIcon(KisIconUtils::loadIcon("symmetry-horizontal")); m_vMirrorAction->setIcon(KisIconUtils::loadIcon("symmetry-vertical")); KisConfig cfg(true); if (!cfg.toolOptionsInDocker() && m_toolOptionsPopupButton) { m_toolOptionsPopupButton->setIcon(KisIconUtils::loadIcon("configure")); } m_presetSelectorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_01")); m_brushEditorPopupButton->setIcon(KisIconUtils::loadIcon("paintop_settings_02")); m_workspaceWidget->setIcon(KisIconUtils::loadIcon("view-choose")); m_eraseAction->setIcon(KisIconUtils::loadIcon("draw-eraser")); m_reloadAction->setIcon(KisIconUtils::loadIcon("view-refresh")); if (m_disablePressureAction->isChecked()) { m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure")); } else { m_disablePressureAction->setIcon(KisIconUtils::loadIcon("transform_icons_penPressure_locked")); } } void KisPaintopBox::slotLockXMirrorToggle(bool toggleLock) { m_resourceProvider->setMirrorHorizontalLock(toggleLock); } void KisPaintopBox::slotLockYMirrorToggle(bool toggleLock) { m_resourceProvider->setMirrorVerticalLock(toggleLock); } void KisPaintopBox::slotHideDecorationMirrorX(bool toggled) { m_resourceProvider->setMirrorHorizontalHideDecorations(toggled); } void KisPaintopBox::slotHideDecorationMirrorY(bool toggled) { m_resourceProvider->setMirrorVerticalHideDecorations(toggled); } void KisPaintopBox::slotMoveToCenterMirrorX() { m_resourceProvider->mirrorHorizontalMoveCanvasToCenter(); } void KisPaintopBox::slotMoveToCenterMirrorY() { m_resourceProvider->mirrorVerticalMoveCanvasToCenter(); } diff --git a/libs/ui/kis_paintop_box.h b/libs/ui/kis_paintop_box.h index 4e5edacb30..aae841fd33 100644 --- a/libs/ui/kis_paintop_box.h +++ b/libs/ui/kis_paintop_box.h @@ -1,271 +1,269 @@ /* * kis_paintop_box.h - part of KImageShop/Krayon/Krita * * Copyright (c) 2004-2008 Boudewijn Rempt (boud@valdyas.org) * Copyright (C) 2011 Silvio Heinrich * * 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_PAINTOP_BOX_H_ #define KIS_PAINTOP_BOX_H_ #include #include #include - +#include #include #include #include #include #include #include #include #include "kritaui_export.h" #include "kis_signal_auto_connection.h" #include "kis_signal_compressor.h" - class QToolButton; class QString; class QHBoxLayout; class KoColorSpace; -class KoResource; class KoCanvasController; class KisViewManager; class KisCanvasResourceProvider; class KisPopupButton; class KisIconWidget; class KisToolOptionsPopup; class KisPaintOpPresetsPopup; class KisPaintOpPresetsChooserPopup; class KisPaintOpConfigWidget; class KisCompositeOpComboBox; class KisWidgetChooser; class KisFavoriteResourceManager; class KisAction; class KisPresetSaveWidget; /** * This widget presents all paintops that a user can paint with. * Paintops represent real-world tools or the well-known Shoup * computer equivalents that do nothing but change color. * * To incorporate the dirty preset functionality and locked settings * the following slots are added * void slotReloadPreset(); void slotGuiChangedCurrentPreset(); void slotSaveLockedOptionToPreset(KisPropertiesConfigurationSP p); void slotDropLockedOption(KisPropertiesConfigurationSP p); void slotDirtyPresetToggled(bool); Every time a value is changed in a preset, the preset is made dirty through the onChange() function. For Locked Settings however, a changed Locked Setting will not cause a preset to become dirty. That is because it borrows its values from the KisLockedPropertiesServer. Hence the dirty state of the Preset is kept consistent before and after a writeConfiguration operation in most cases. * XXX: When we have a lot of paintops, replace the listbox * with a table, and for every category a combobox. * * XXX: instead of text, use pretty pictures. */ class KRITAUI_EXPORT KisPaintopBox : public QWidget { Q_OBJECT enum { ENABLE_PRESETS = 0x0001, DISABLE_PRESETS = 0x0002, ENABLE_COMPOSITEOP = 0x0004, DISABLE_COMPOSITEOP = 0x0008, ENABLE_OPACITY = 0x0010, DISABLE_OPACITY = 0x0020, ENABLE_FLOW = 0x0040, DISABLE_FLOW = 0x0080, ENABLE_SIZE = 0x0100, DISABLE_SIZE = 0x0200, ENABLE_ALL = 0x5555, DISABLE_ALL = 0xAAAA }; public: KisPaintopBox(KisViewManager* view, QWidget* parent, const char* name); ~KisPaintopBox() override; - void restoreResource(KoResource* resource); + void restoreResource(KoResourceSP resource); /** * Update the option widgets to the argument ones, removing the currently set widgets. */ void newOptionWidgets(const QList > & optionWidgetList); KisFavoriteResourceManager *favoriteResourcesManager() { return m_favoriteResourceManager; } public Q_SLOTS: void slotColorSpaceChanged(const KoColorSpace* colorSpace); void slotInputDeviceChanged(const KoInputDevice & inputDevice); void slotCanvasResourceChanged(int key, const QVariant& v); - void resourceSelected(KoResource* resource); + void resourceSelected(KoResourceSP resource); /// This should take care of creating a new brush preset from scratch /// It will either load the default brush preset for the engine, /// or create a new empty preset if a default preset does not exist void slotCreatePresetFromScratch(QString paintop); private: void setCurrentPaintop(const KoID& paintop); void setCurrentPaintop(KisPaintOpPresetSP preset); KisPaintOpPresetSP defaultPreset(const KoID& paintOp); KisPaintOpPresetSP activePreset(const KoID& paintOp); void updateCompositeOp(QString compositeOpID); void setWidgetState(int flags); void setSliderValue(const QString& sliderID, qreal value); void sliderChanged(int n); private Q_SLOTS: void slotUpdatePreset(); void slotSetupDefaultPreset(); void slotNodeChanged(const KisNodeSP node); void slotToggleEraseMode(bool checked); void slotSetCompositeMode(int index); void slotSetPaintop(const QString& paintOpId); void slotHorizontalMirrorChanged(bool value); void slotVerticalMirrorChanged(bool value); void slotSlider1Changed(); void slotSlider2Changed(); void slotSlider3Changed(); void slotToolChanged(KoCanvasController* canvas, int toolId); void slotPreviousFavoritePreset(); void slotNextFavoritePreset(); void slotSwitchToPreviousPreset(); void slotUnsetEraseMode(); void slotToggleAlphaLockMode(bool); void slotDisablePressureMode(bool); void slotReloadPreset(); void slotGuiChangedCurrentPreset(); void slotSaveLockedOptionToPreset(KisPropertiesConfigurationSP p); void slotDropLockedOption(KisPropertiesConfigurationSP p); void slotDirtyPresetToggled(bool); void slotEraserBrushSizeToggled(bool); void slotEraserBrushOpacityToggled(bool); void slotUpdateSelectionIcon(); void slotLockXMirrorToggle(bool); void slotLockYMirrorToggle(bool); void slotMoveToCenterMirrorX(); void slotMoveToCenterMirrorY(); void slotHideDecorationMirrorX(bool); void slotHideDecorationMirrorY(bool); void slotUpdateOptionsWidgetPopup(); private: KisCanvasResourceProvider* m_resourceProvider; QHBoxLayout* m_layout; QWidget* m_paintopWidget; KisPaintOpConfigWidget* m_optionWidget; KisPopupButton* m_toolOptionsPopupButton; KisPresetSaveWidget* m_savePresetWidget; KisIconWidget* m_brushEditorPopupButton; KisPopupButton* m_presetSelectorPopupButton; KisCompositeOpComboBox* m_cmbCompositeOp; QToolButton* m_eraseModeButton; QToolButton* m_alphaLockButton; QToolButton* m_hMirrorButton; QToolButton* m_vMirrorButton; KisToolOptionsPopup* m_toolOptionsPopup; KisPaintOpPresetsPopup* m_presetsPopup; KisPaintOpPresetsChooserPopup* m_presetsChooserPopup; KisViewManager* m_viewManager; KisPopupButton* m_workspaceWidget; KisWidgetChooser* m_sliderChooser[3]; QMap m_paintopOptionWidgets; KisFavoriteResourceManager* m_favoriteResourceManager; QToolButton* m_reloadButton; KisAction* m_eraseAction; KisAction* m_reloadAction; KisAction* m_disablePressureAction; QString m_currCompositeOpID; KisNodeWSP m_previousNode; KisAction* m_hMirrorAction; KisAction* m_vMirrorAction; KisAction* hideCanvasDecorationsX; KisAction* lockActionX; KisAction* moveToCenterActionX; KisAction* hideCanvasDecorationsY; KisAction* lockActionY; KisAction* moveToCenterActionY; struct TabletToolID { TabletToolID(const KoInputDevice& dev) { uniqueID = dev.uniqueTabletId(); // Only the eraser is special, and we don't look at Cursor pointer = QTabletEvent::Pen; if (dev.pointer() == QTabletEvent::Eraser) { pointer = QTabletEvent::Eraser; } } bool operator == (const TabletToolID& id) const { return pointer == id.pointer && uniqueID == id.uniqueID; } bool operator < (const TabletToolID& id) const { if (uniqueID == id.uniqueID) return pointer < id.pointer; return uniqueID < id.uniqueID; } QTabletEvent::PointerType pointer; qint64 uniqueID; }; struct TabletToolData { KoID paintOpID; KisPaintOpPresetSP preset; }; typedef QMap TabletToolMap; typedef QMap PaintOpPresetMap; TabletToolMap m_tabletToolMap; PaintOpPresetMap m_paintOpPresetMap; TabletToolID m_currTabletToolID; bool m_presetsEnabled; bool m_blockUpdate; bool m_dirtyPresetsEnabled; bool m_eraserBrushSizeEnabled; bool m_eraserBrushOpacityEnabled; KisSignalAutoConnectionsStore m_presetConnections; QString m_eraserName; QString m_defaultPresetName; }; #endif //KIS_PAINTOP_BOX_H_ diff --git a/libs/ui/kis_psd_layer_style_resource.h b/libs/ui/kis_psd_layer_style_resource.h index a1329296b2..f403e934e2 100644 --- a/libs/ui/kis_psd_layer_style_resource.h +++ b/libs/ui/kis_psd_layer_style_resource.h @@ -1,63 +1,65 @@ /* * Copyright (c) 2014 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. */ #ifndef KIS_PSD_LAYER_STYLE_RESOURCE_H #define KIS_PSD_LAYER_STYLE_RESOURCE_H #include #include #include #include "kis_psd_layer_style.h" /** * @brief The KisPSDLayerStyleResource class represents an ASL file type resource. */ class KRITAUI_EXPORT KisPSDLayerStyleCollectionResource : public KoResource { public: typedef QVector StylesVector; public: explicit KisPSDLayerStyleCollectionResource(const QString &filename); ~KisPSDLayerStyleCollectionResource() override; bool load() override; bool loadFromDevice(QIODevice *dev) override; bool save() override; bool saveToDevice(QIODevice *dev) const override; QString defaultFileExtension() const override; StylesVector layerStyles() const; void setLayerStyles(StylesVector styles); void collectAllLayerStyles(KisNodeSP root); void assignAllLayerStyles(KisNodeSP root); protected: QByteArray generateMD5() const override; private: StylesVector m_layerStyles; }; +typedef QSharedPointer KisPSDLayerStyleCollectionResourceSP; + #endif // KIS_PSD_LAYER_STYLE_RESOURCE_H diff --git a/libs/ui/kis_stopgradient_editor.cpp b/libs/ui/kis_stopgradient_editor.cpp index f5f1eb50a3..ed7f374d0e 100644 --- a/libs/ui/kis_stopgradient_editor.cpp +++ b/libs/ui/kis_stopgradient_editor.cpp @@ -1,198 +1,197 @@ /* * 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 "kis_debug.h" #include /****************************** KisStopGradientEditor ******************************/ KisStopGradientEditor::KisStopGradientEditor(QWidget *parent) : QWidget(parent), m_gradient(0) { 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))); opacitySlider->setPrefix(i18n("Opacity: ")); opacitySlider->setRange(0.0, 1.0, 2); connect(opacitySlider, SIGNAL(valueChanged(qreal)), this, SLOT(opacityChanged(qreal))); buttonReverse->setIcon(KisIconUtils::loadIcon("view-refresh")); buttonReverse->setToolTip(i18n("Flip Gradient")); KisIconUtils::updateIcon(buttonReverse); connect(buttonReverse, SIGNAL(pressed()), SLOT(reverse())); buttonReverseSecond->setIcon(KisIconUtils::loadIcon("view-refresh")); buttonReverseSecond->setToolTip(i18n("Flip Gradient")); KisIconUtils::updateIcon(buttonReverseSecond); connect(buttonReverseSecond, SIGNAL(clicked()), SLOT(reverse())); setCompactMode(false); setGradient(0); stopChanged(-1); } -KisStopGradientEditor::KisStopGradientEditor(KoStopGradient* gradient, QWidget *parent, const char* name, const QString& caption) +KisStopGradientEditor::KisStopGradientEditor(KoStopGradientSP gradient, QWidget *parent, const char* name, const QString& caption) : KisStopGradientEditor(parent) { setObjectName(name); setWindowTitle(caption); - setGradient(gradient); } void KisStopGradientEditor::setCompactMode(bool value) { lblName->setVisible(!value); buttonReverse->setVisible(!value); nameedit->setVisible(!value); buttonReverseSecond->setVisible(value); } -void KisStopGradientEditor::setGradient(KoStopGradient *gradient) +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); if (hasStopSelected) { KoColor color = m_gradient->stops()[stop].second; opacitySlider->setValue(color.opacityF()); color.setOpacity(1.0); colorButton->setColor(color); } emit sigGradientChanged(); } void KisStopGradientEditor::colorChanged(const KoColor& color) { if (!m_gradient) return; QList stops = m_gradient->stops(); int currentStop = gradientSlider->selectedStop(); double t = stops[currentStop].first; KoColor c(color, stops[currentStop].second.colorSpace()); c.setOpacity(stops[currentStop].second.opacityU8()); stops.removeAt(currentStop); stops.insert(currentStop, KoGradientStop(t, c)); m_gradient->setStops(stops); gradientSlider->update(); emit sigGradientChanged(); } void KisStopGradientEditor::opacityChanged(qreal value) { if (!m_gradient) return; QList stops = m_gradient->stops(); int currentStop = gradientSlider->selectedStop(); double t = stops[currentStop].first; KoColor c = stops[currentStop].second; c.setOpacity(value); stops.removeAt(currentStop); stops.insert(currentStop, KoGradientStop(t, c)); m_gradient->setStops(stops); gradientSlider->update(); emit sigGradientChanged(); } void KisStopGradientEditor::nameChanged() { if (!m_gradient) return; m_gradient->setName(nameedit->text()); emit sigGradientChanged(); } void KisStopGradientEditor::reverse() { if (!m_gradient) return; QList stops = m_gradient->stops(); QList reversedStops; for(const KoGradientStop& stop : stops) { reversedStops.push_front(KoGradientStop(1 - stop.first, stop.second)); } m_gradient->setStops(reversedStops); gradientSlider->setSelectedStop(stops.size() - 1 - gradientSlider->selectedStop()); emit sigGradientChanged(); } diff --git a/libs/ui/kis_stopgradient_editor.h b/libs/ui/kis_stopgradient_editor.h index 65dfb4d335..61a386fa6a 100644 --- a/libs/ui/kis_stopgradient_editor.h +++ b/libs/ui/kis_stopgradient_editor.h @@ -1,58 +1,57 @@ /* * Copyright (c) 2004 Cyrille Berger * 2016 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KIS_STOPGRADIENT_EDITOR_H_ #define _KIS_STOPGRADIENT_EDITOR_H_ #include "kritaui_export.h" #include "ui_wdgstopgradienteditor.h" #include - -class KoStopGradient; +#include class KRITAUI_EXPORT KisStopGradientEditor : public QWidget, public Ui::KisWdgStopGradientEditor { Q_OBJECT public: KisStopGradientEditor(QWidget *parent); - KisStopGradientEditor(KoStopGradient* gradient, QWidget *parent, const char* name, const QString& caption); + KisStopGradientEditor(KoStopGradientSP gradient, QWidget *parent, const char* name, const QString& caption); void setCompactMode(bool value); - void setGradient(KoStopGradient* gradient); + void setGradient(KoStopGradientSP gradient); void notifyGlobalColorChanged(const KoColor &color); boost::optional currentActiveStopColor() const; Q_SIGNALS: void sigGradientChanged(); private: - KoStopGradient* m_gradient; + KoStopGradientSP m_gradient; private Q_SLOTS: void stopChanged(int stop); void colorChanged(const KoColor& color); void opacityChanged(qreal value); void nameChanged(); void reverse(); }; #endif diff --git a/libs/ui/kis_workspace_resource.h b/libs/ui/kis_workspace_resource.h index 536f68cc5a..66ded26045 100644 --- a/libs/ui/kis_workspace_resource.h +++ b/libs/ui/kis_workspace_resource.h @@ -1,47 +1,49 @@ /* This file is part of the KDE project * Copyright (C) 2011 Sven Langkamp * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KIS_WORKSPACE_RESOURCE_H #define KIS_WORKSPACE_RESOURCE_H #include #include #include "kritaui_export.h" /// Resource for storing of workspaces class KRITAUI_EXPORT KisWorkspaceResource : public KoResource , public KisPropertiesConfiguration { public: KisWorkspaceResource(const QString& filename); ~KisWorkspaceResource() override; bool load() override; bool loadFromDevice(QIODevice *dev) override; bool save() override; bool saveToDevice(QIODevice* dev) const override; QString defaultFileExtension() const override; void setDockerState(const QByteArray& state); QByteArray dockerState(); private: QByteArray m_dockerState; }; +typedef QSharedPointer KisWorkspaceResourceSP; + #endif // KIS_WORKSPACE_RESOURCE_H diff --git a/libs/ui/tests/fill_processing_visitor_test.cpp b/libs/ui/tests/fill_processing_visitor_test.cpp index 222e8a8dca..92e32c1cc9 100644 --- a/libs/ui/tests/fill_processing_visitor_test.cpp +++ b/libs/ui/tests/fill_processing_visitor_test.cpp @@ -1,145 +1,145 @@ /* * Copyright (c) 2013 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 "fill_processing_visitor_test.h" #include #include "kis_undo_stores.h" #include "kis_processing_applicator.h" #include "testutil.h" #include "qimage_based_test.h" #include "stroke_testing_utils.h" #include #include "kis_canvas_resource_provider.h" #include class FillProcessingVisitorTester : public TestUtil::QImageBasedTest { public: FillProcessingVisitorTester() : QImageBasedTest("fill_processing") { } void test(const QString &testname, bool haveSelection, bool usePattern, bool selectionOnly) { KisSurrogateUndoStore *undoStore = new KisSurrogateUndoStore(); KisImageSP image = createImage(undoStore); if (haveSelection) { addGlobalSelection(image); } image->initialRefreshGraph(); QVERIFY(checkLayersInitial(image)); KisNodeSP fillNode = findNode(image->root(), "paint1"); KoCanvasResourceProvider *manager = utils::createResourceManager(image, fillNode); - KoPattern *newPattern = new KoPattern(TestUtil::fetchDataFileLazy("HR_SketchPaper_01.pat")); + KoPatternSP newPattern(new KoPattern(TestUtil::fetchDataFileLazy("HR_SketchPaper_01.pat"))); newPattern->load(); Q_ASSERT(newPattern->valid()); QVariant v; - v.setValue(static_cast(newPattern)); + v.setValue(newPattern); manager->setResource(KisCanvasResourceProvider::CurrentPattern, v); KisResourcesSnapshotSP resources = new KisResourcesSnapshot(image, fillNode, manager); KisProcessingVisitorSP visitor = new FillProcessingVisitor(QPoint(100,100), image->globalSelection(), resources, false, // useFastMode usePattern, selectionOnly, 10, 10, 10, true, false); KisProcessingApplicator applicator(image, fillNode, KisProcessingApplicator::NONE); applicator.applyVisitor(visitor); applicator.end(); image->waitForDone(); QVERIFY(checkOneLayer(image, fillNode, testname, 500)); undoStore->undo(); image->waitForDone(); QVERIFY(checkLayersInitial(image)); } }; void FillProcessingVisitorTest::testFillColorNoSelection() { FillProcessingVisitorTester tester; tester.test("fill_color_no_selection", false, false, false); } void FillProcessingVisitorTest::testFillPatternNoSelection() { FillProcessingVisitorTester tester; tester.test("fill_pattern_no_selection", false, true, false); } void FillProcessingVisitorTest::testFillColorHaveSelection() { FillProcessingVisitorTester tester; tester.test("fill_color_have_selection", true, false, false); } void FillProcessingVisitorTest::testFillPatternHaveSelection() { FillProcessingVisitorTester tester; tester.test("fill_pattern_have_selection", true, true, false); } void FillProcessingVisitorTest::testFillColorNoSelectionSelectionOnly() { FillProcessingVisitorTester tester; tester.test("fill_color_no_selection_selection_only", false, false, true); } void FillProcessingVisitorTest::testFillPatternNoSelectionSelectionOnly() { FillProcessingVisitorTester tester; tester.test("fill_pattern_no_selection_selection_only", false, true, true); } void FillProcessingVisitorTest::testFillColorHaveSelectionSelectionOnly() { FillProcessingVisitorTester tester; tester.test("fill_color_have_selection_selection_only", true, false, true); } void FillProcessingVisitorTest::testFillPatternHaveSelectionSelectionOnly() { FillProcessingVisitorTester tester; tester.test("fill_pattern_have_selection_selection_only", true, true, true); } QTEST_MAIN(FillProcessingVisitorTest) diff --git a/libs/ui/tests/kis_asl_layer_style_serializer_test.cpp b/libs/ui/tests/kis_asl_layer_style_serializer_test.cpp index 73fb569553..16a7e189bb 100644 --- a/libs/ui/tests/kis_asl_layer_style_serializer_test.cpp +++ b/libs/ui/tests/kis_asl_layer_style_serializer_test.cpp @@ -1,425 +1,425 @@ /* * 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(); - QList sortedResources = server->sortedResources(); + QList sortedResources = server->sortedResources(); - KoPattern *pattern = sortedResources.first(); + KoPatternSP pattern = sortedResources.first(); 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)); 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/ui/tests/kis_derived_resources_test.cpp b/libs/ui/tests/kis_derived_resources_test.cpp index c480f36624..9c80b5876e 100644 --- a/libs/ui/tests/kis_derived_resources_test.cpp +++ b/libs/ui/tests/kis_derived_resources_test.cpp @@ -1,159 +1,156 @@ /* * Copyright (c) 2016 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_derived_resources_test.h" #include #include #include #include #include "kis_canvas_resource_provider.h" #include #include #include #include #include #include #include #include #include #include "testutil.h" #include "opengl/kis_opengl.h" void addResourceTypes() { // All Krita's resource types KoResourcePaths::addResourceType("gmic_definitions", "data", "/gmic/"); KoResourcePaths::addResourceType("icc_profiles", "data", "/color/icc"); KoResourcePaths::addResourceType("icc_profiles", "data", "/profiles/"); KoResourcePaths::addResourceType("kis_actions", "data", "/actions"); KoResourcePaths::addResourceType("brushes", "data", "/brushes/"); KoResourcePaths::addResourceType("kis_defaultpresets", "data", "/defaultpresets/"); KoResourcePaths::addResourceType("kis_images", "data", "/images/"); KoResourcePaths::addResourceType("paintoppresets", "data", "/paintoppresets/"); KoResourcePaths::addResourceType("kis_pics", "data", "/pics/"); KoResourcePaths::addResourceType("kis_resourcebundles", "data", "/bundles/"); KoResourcePaths::addResourceType("kis_shortcuts", "data", "/shortcuts/"); KoResourcePaths::addResourceType("kis_taskset", "data", "/taskset/"); KoResourcePaths::addResourceType("kis_taskset", "data", "/taskset/"); KoResourcePaths::addResourceType("windowlayouts", "data", "/windowlayouts/"); KoResourcePaths::addResourceType("workspaces", "data", "/workspaces/"); KoResourcePaths::addResourceType("ko_effects", "data", "/effects/"); KoResourcePaths::addResourceType("gradients", "data", "/gradients/"); KoResourcePaths::addResourceType("palettes", "data", "/palettes/"); KoResourcePaths::addResourceType("patterns", "data", "/patterns/"); KoResourcePaths::addResourceType("metadata_schema", "data", "/metadata/schemas/"); KoResourcePaths::addResourceType("psd_layer_style_collections", "data", "/asl"); KoResourcePaths::addResourceType("tags", "data", "/tags/"); KisOpenGL::setDefaultFormat(false, false); KisConfig cfg(false); cfg.setUseOpenGL(false); } void KisDerivedResourcesTest::test() { addResourceTypes(); KisDocument* doc = createEmptyDocument(); - - KisMainWindow* mainWindow = KisPart::instance()->createMainWindow(); QPointer view = new KisView(doc, mainWindow->resourceManager(), mainWindow->actionCollection(), mainWindow); KisViewManager *viewManager = new KisViewManager(mainWindow, mainWindow->actionCollection()); KoCanvasResourceProvider *manager = viewManager->resourceProvider()->resourceManager(); QApplication::processEvents(); QString presetFileName = "autobrush_300px.kpp"; QVariant i; KisPaintOpPresetSP preset; if (!presetFileName.isEmpty()) { QString fullFileName = TestUtil::fetchDataFileLazy(presetFileName); - preset = new KisPaintOpPreset(fullFileName); + preset = KisPaintOpPresetSP(new KisPaintOpPreset(fullFileName)); bool presetValid = preset->load(); Q_ASSERT(presetValid); Q_UNUSED(presetValid); i.setValue(preset); - } QVERIFY(i.isValid()); QSignalSpy spy(manager, SIGNAL(canvasResourceChanged(int,QVariant))); manager->setResource(KisCanvasResourceProvider::CurrentPaintOpPreset, i); QMap expectedSignals; expectedSignals[KisCanvasResourceProvider::CurrentPaintOpPreset] = QVariant::fromValue(preset); expectedSignals[KisCanvasResourceProvider::EraserMode] = false; expectedSignals[KisCanvasResourceProvider::LodSizeThresholdSupported] = true; expectedSignals[KisCanvasResourceProvider::EffectiveLodAvailablility] = true; expectedSignals[KisCanvasResourceProvider::LodSizeThreshold] = 100; expectedSignals[KisCanvasResourceProvider::LodAvailability] = true; expectedSignals[KisCanvasResourceProvider::Opacity] = 1.0; expectedSignals[KisCanvasResourceProvider::Size] = 300.0; expectedSignals[KisCanvasResourceProvider::Flow] = 1.0; expectedSignals[KisCanvasResourceProvider::CurrentEffectiveCompositeOp] = COMPOSITE_OVER; expectedSignals[KisCanvasResourceProvider::CurrentCompositeOp] = COMPOSITE_OVER; auto it = spy.begin(); for (; it != spy.end(); ++it) { const int id = (*it)[0].toInt(); const QVariant value = (*it)[1]; if (!expectedSignals.contains(id)) { qDebug() << ppVar(id) << ppVar(value); QFAIL("Unexpected signal!"); } else { if (expectedSignals[id] != value) { qDebug() << ppVar(id) << ppVar(value) << ppVar(expectedSignals[id]); QFAIL("Unexpected value!"); } } } QCOMPARE(spy.size(), expectedSignals.size()); spy.clear(); preset->settings()->setPaintOpOpacity(0.8); QCOMPARE(spy.size(), 1); QCOMPARE(spy[0][0].toInt(), (int)KisCanvasResourceProvider::Opacity); QCOMPARE(spy[0][1].toDouble(), 0.8); spy.clear(); mainWindow->hide(); QApplication::processEvents(); delete view; delete doc; delete mainWindow; } KISTEST_MAIN(KisDerivedResourcesTest) diff --git a/libs/ui/tests/kis_stop_gradient_editor_test.cpp b/libs/ui/tests/kis_stop_gradient_editor_test.cpp index 4d332ad294..290876f723 100644 --- a/libs/ui/tests/kis_stop_gradient_editor_test.cpp +++ b/libs/ui/tests/kis_stop_gradient_editor_test.cpp @@ -1,50 +1,50 @@ /* * Copyright (c) 2016 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_stop_gradient_editor_test.h" #include #include #include #include #include "kis_debug.h" #include "kis_stopgradient_editor.h" void KisStopGradientEditorTest::test() { QLinearGradient gradient; - QScopedPointer koGradient(KoStopGradient::fromQGradient(&gradient)); + QSharedPointer koGradient(KoStopGradient::fromQGradient(&gradient)); QDialog dlg; KisStopGradientEditor *widget = new KisStopGradientEditor(&dlg); - widget->setGradient(koGradient.data()); + widget->setGradient(koGradient); QVBoxLayout *layout = new QVBoxLayout(&dlg); layout->setContentsMargins(0,0,0,0); layout->addWidget(widget); dlg.setLayout(layout); dlg.setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); //dlg.exec(); qWarning() << "WARNING: showing of the dialogs in the unittest is disabled!"; } QTEST_MAIN(KisStopGradientEditorTest) diff --git a/libs/ui/tool/kis_resources_snapshot.cpp b/libs/ui/tool/kis_resources_snapshot.cpp index df7192d45e..8c564d9dcf 100644 --- a/libs/ui/tool/kis_resources_snapshot.cpp +++ b/libs/ui/tool/kis_resources_snapshot.cpp @@ -1,415 +1,415 @@ /* * Copyright (c) 2011 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_resources_snapshot.h" #include #include #include #include #include #include #include #include #include "kis_canvas_resource_provider.h" #include "filter/kis_filter_configuration.h" #include "kis_image.h" #include "kis_paint_device.h" #include "kis_paint_layer.h" #include "kis_selection.h" #include "kis_selection_mask.h" #include "kis_algebra_2d.h" struct KisResourcesSnapshot::Private { Private() : currentPattern(0) , currentGradient(0) , currentGenerator(0) , compositeOp(0) { } KisImageSP image; KisDefaultBoundsBaseSP bounds; KoColor currentFgColor; KoColor currentBgColor; - KoPattern *currentPattern = 0; - KoAbstractGradient *currentGradient; + KoPatternSP currentPattern; + KoAbstractGradientSP currentGradient; KisPaintOpPresetSP currentPaintOpPreset; KisNodeSP currentNode; qreal currentExposure; KisFilterConfigurationSP currentGenerator; QPointF axesCenter; bool mirrorMaskHorizontal = false; bool mirrorMaskVertical = false; quint8 opacity = OPACITY_OPAQUE_U8; QString compositeOpId = COMPOSITE_OVER; const KoCompositeOp *compositeOp; KisPainter::StrokeStyle strokeStyle = KisPainter::StrokeStyleBrush; KisPainter::FillStyle fillStyle = KisPainter::FillStyleForegroundColor; bool globalAlphaLock = false; qreal effectiveZoom = 1.0; bool presetAllowsLod = false; KisSelectionSP selectionOverride; }; KisResourcesSnapshot::KisResourcesSnapshot(KisImageSP image, KisNodeSP currentNode, KoCanvasResourceProvider *resourceManager, KisDefaultBoundsBaseSP bounds) : m_d(new Private()) { m_d->image = image; if (!bounds) { bounds = new KisDefaultBounds(m_d->image); } m_d->bounds = bounds; m_d->currentFgColor = resourceManager->resource(KoCanvasResourceProvider::ForegroundColor).value(); m_d->currentBgColor = resourceManager->resource(KoCanvasResourceProvider::BackgroundColor).value(); - m_d->currentPattern = resourceManager->resource(KisCanvasResourceProvider::CurrentPattern).value(); - m_d->currentGradient = resourceManager->resource(KisCanvasResourceProvider::CurrentGradient).value(); + m_d->currentPattern = resourceManager->resource(KisCanvasResourceProvider::CurrentPattern).value(); + m_d->currentGradient = resourceManager->resource(KisCanvasResourceProvider::CurrentGradient).value(); /** * We should deep-copy the preset, so that long-running actions * will have correct brush parameters. Theoretically this cloning * can be expensive, but according to measurements, it takes * something like 0.1 ms for an average preset. */ KisPaintOpPresetSP p = resourceManager->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value(); if (p) { m_d->currentPaintOpPreset = resourceManager->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value()->clone(); } #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND KisPaintOpRegistry::instance()->preinitializePaintOpIfNeeded(m_d->currentPaintOpPreset); #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ m_d->currentExposure = resourceManager->resource(KisCanvasResourceProvider::HdrExposure).toDouble(); m_d->currentGenerator = resourceManager->resource(KisCanvasResourceProvider::CurrentGeneratorConfiguration).value(); QPointF relativeAxesCenter(0.5, 0.5); if (m_d->image) { relativeAxesCenter = m_d->image->mirrorAxesCenter(); } m_d->axesCenter = KisAlgebra2D::relativeToAbsolute(relativeAxesCenter, m_d->bounds->bounds()); m_d->mirrorMaskHorizontal = resourceManager->resource(KisCanvasResourceProvider::MirrorHorizontal).toBool(); m_d->mirrorMaskVertical = resourceManager->resource(KisCanvasResourceProvider::MirrorVertical).toBool(); qreal normOpacity = resourceManager->resource(KisCanvasResourceProvider::Opacity).toDouble(); m_d->opacity = quint8(normOpacity * OPACITY_OPAQUE_U8); m_d->compositeOpId = resourceManager->resource(KisCanvasResourceProvider::CurrentEffectiveCompositeOp).toString(); setCurrentNode(currentNode); /** * Fill and Stroke styles are not a part of the resource manager * so the tools should set them manually * TODO: port stroke and fill styles to be a part * of the resource manager */ m_d->strokeStyle = KisPainter::StrokeStyleBrush; m_d->fillStyle = KisPainter::FillStyleNone; m_d->globalAlphaLock = resourceManager->resource(KisCanvasResourceProvider::GlobalAlphaLock).toBool(); m_d->effectiveZoom = resourceManager->resource(KisCanvasResourceProvider::EffectiveZoom).toDouble(); m_d->presetAllowsLod = resourceManager->resource(KisCanvasResourceProvider::EffectiveLodAvailablility).toBool(); } KisResourcesSnapshot::KisResourcesSnapshot(KisImageSP image, KisNodeSP currentNode, KisDefaultBoundsBaseSP bounds) : m_d(new Private()) { m_d->image = image; if (!bounds) { bounds = new KisDefaultBounds(m_d->image); } m_d->bounds = bounds; #ifdef HAVE_THREADED_TEXT_RENDERING_WORKAROUND KisPaintOpRegistry::instance()->preinitializePaintOpIfNeeded(m_d->currentPaintOpPreset); #endif /* HAVE_THREADED_TEXT_RENDERING_WORKAROUND */ QPointF relativeAxesCenter(0.5, 0.5); if (m_d->image) { relativeAxesCenter = m_d->image->mirrorAxesCenter(); } m_d->axesCenter = KisAlgebra2D::relativeToAbsolute(relativeAxesCenter, m_d->bounds->bounds()); m_d->opacity = OPACITY_OPAQUE_U8; setCurrentNode(currentNode); /** * Fill and Stroke styles are not a part of the resource manager * so the tools should set them manually * TODO: port stroke and fill styles to be a part * of the resource manager */ m_d->strokeStyle = KisPainter::StrokeStyleBrush; m_d->fillStyle = KisPainter::FillStyleNone; } KisResourcesSnapshot::~KisResourcesSnapshot() { delete m_d; } void KisResourcesSnapshot::setupPainter(KisPainter* painter) { painter->setPaintColor(m_d->currentFgColor); painter->setBackgroundColor(m_d->currentBgColor); painter->setGenerator(m_d->currentGenerator); painter->setPattern(m_d->currentPattern); painter->setGradient(m_d->currentGradient); QBitArray lockflags = channelLockFlags(); if (lockflags.size() > 0) { painter->setChannelFlags(lockflags); } painter->setOpacity(m_d->opacity); painter->setCompositeOp(m_d->compositeOp); painter->setMirrorInformation(m_d->axesCenter, m_d->mirrorMaskHorizontal, m_d->mirrorMaskVertical); painter->setStrokeStyle(m_d->strokeStyle); painter->setFillStyle(m_d->fillStyle); /** * The paintOp should be initialized the last, because it may * ask the painter for some options while initialization */ painter->setPaintOpPreset(m_d->currentPaintOpPreset, m_d->currentNode, m_d->image); } void KisResourcesSnapshot::setupMaskingBrushPainter(KisPainter *painter) { KIS_SAFE_ASSERT_RECOVER_RETURN(painter->device()); KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->currentPaintOpPreset->hasMaskingPreset()); painter->setPaintColor(KoColor(Qt::white, painter->device()->colorSpace())); painter->setBackgroundColor(KoColor(Qt::black, painter->device()->colorSpace())); painter->setOpacity(OPACITY_OPAQUE_U8); painter->setChannelFlags(QBitArray()); // masked brush always paints in indirect mode painter->setCompositeOp(COMPOSITE_ALPHA_DARKEN); painter->setMirrorInformation(m_d->axesCenter, m_d->mirrorMaskHorizontal, m_d->mirrorMaskVertical); /** * The paintOp should be initialized the last, because it may * ask the painter for some options while initialization */ painter->setPaintOpPreset(m_d->currentPaintOpPreset->createMaskingPreset(), m_d->currentNode, m_d->image); } KisPostExecutionUndoAdapter* KisResourcesSnapshot::postExecutionUndoAdapter() const { return m_d->image ? m_d->image->postExecutionUndoAdapter() : 0; } void KisResourcesSnapshot::setCurrentNode(KisNodeSP node) { m_d->currentNode = node; KisPaintDeviceSP device; if(m_d->currentNode && (device = m_d->currentNode->paintDevice())) { m_d->compositeOp = device->colorSpace()->compositeOp(m_d->compositeOpId); if(!m_d->compositeOp) { m_d->compositeOp = device->colorSpace()->compositeOp(COMPOSITE_OVER); } } } void KisResourcesSnapshot::setStrokeStyle(KisPainter::StrokeStyle strokeStyle) { m_d->strokeStyle = strokeStyle; } void KisResourcesSnapshot::setFillStyle(KisPainter::FillStyle fillStyle) { m_d->fillStyle = fillStyle; } KisNodeSP KisResourcesSnapshot::currentNode() const { return m_d->currentNode; } KisImageSP KisResourcesSnapshot::image() const { return m_d->image; } bool KisResourcesSnapshot::needsIndirectPainting() const { return !m_d->currentPaintOpPreset->settings()->paintIncremental(); } QString KisResourcesSnapshot::indirectPaintingCompositeOp() const { return m_d->currentPaintOpPreset ? m_d->currentPaintOpPreset->settings()->indirectPaintingCompositeOp() : COMPOSITE_ALPHA_DARKEN; } bool KisResourcesSnapshot::needsMaskingBrushRendering() const { return m_d->currentPaintOpPreset && m_d->currentPaintOpPreset->hasMaskingPreset(); } KisSelectionSP KisResourcesSnapshot::activeSelection() const { /** * It is possible to have/use the snapshot without the image. Such * usecase is present for example in the scratchpad. */ if (m_d->selectionOverride) { return m_d->selectionOverride; } KisSelectionSP selection = m_d->image ? m_d->image->globalSelection() : 0; KisLayerSP layer = qobject_cast(m_d->currentNode.data()); KisSelectionMaskSP mask; if((layer = qobject_cast(m_d->currentNode.data()))) { selection = layer->selection(); } else if ((mask = dynamic_cast(m_d->currentNode.data())) && mask->selection() == selection) { selection = 0; } return selection; } bool KisResourcesSnapshot::needsAirbrushing() const { return m_d->currentPaintOpPreset->settings()->isAirbrushing(); } qreal KisResourcesSnapshot::airbrushingInterval() const { return m_d->currentPaintOpPreset->settings()->airbrushInterval(); } bool KisResourcesSnapshot::needsSpacingUpdates() const { return m_d->currentPaintOpPreset->settings()->useSpacingUpdates(); } void KisResourcesSnapshot::setOpacity(qreal opacity) { m_d->opacity = opacity * OPACITY_OPAQUE_U8; } quint8 KisResourcesSnapshot::opacity() const { return m_d->opacity; } const KoCompositeOp* KisResourcesSnapshot::compositeOp() const { return m_d->compositeOp; } QString KisResourcesSnapshot::compositeOpId() const { return m_d->compositeOpId; } -KoPattern* KisResourcesSnapshot::currentPattern() const +KoPatternSP KisResourcesSnapshot::currentPattern() const { return m_d->currentPattern; } KoColor KisResourcesSnapshot::currentFgColor() const { return m_d->currentFgColor; } KoColor KisResourcesSnapshot::currentBgColor() const { return m_d->currentBgColor; } KisPaintOpPresetSP KisResourcesSnapshot::currentPaintOpPreset() const { return m_d->currentPaintOpPreset; } QBitArray KisResourcesSnapshot::channelLockFlags() const { QBitArray channelFlags; KisPaintLayer *paintLayer; if ((paintLayer = dynamic_cast(m_d->currentNode.data()))) { channelFlags = paintLayer->channelLockFlags(); if (m_d->globalAlphaLock) { if (channelFlags.isEmpty()) { channelFlags = paintLayer->colorSpace()->channelFlags(true, true); } channelFlags &= paintLayer->colorSpace()->channelFlags(true, false); } } return channelFlags; } qreal KisResourcesSnapshot::effectiveZoom() const { return m_d->effectiveZoom; } bool KisResourcesSnapshot::presetAllowsLod() const { return m_d->presetAllowsLod; } bool KisResourcesSnapshot::presetNeedsAsynchronousUpdates() const { return m_d->currentPaintOpPreset && m_d->currentPaintOpPreset->settings()->needsAsynchronousUpdates(); } void KisResourcesSnapshot::setFGColorOverride(const KoColor &color) { m_d->currentFgColor = color; } void KisResourcesSnapshot::setBGColorOverride(const KoColor &color) { m_d->currentBgColor = color; } void KisResourcesSnapshot::setSelectionOverride(KisSelectionSP selection) { m_d->selectionOverride = selection; } void KisResourcesSnapshot::setBrush(const KisPaintOpPresetSP &brush) { m_d->currentPaintOpPreset = brush; } diff --git a/libs/ui/tool/kis_resources_snapshot.h b/libs/ui/tool/kis_resources_snapshot.h index b2361657b6..4e8db07509 100644 --- a/libs/ui/tool/kis_resources_snapshot.h +++ b/libs/ui/tool/kis_resources_snapshot.h @@ -1,106 +1,106 @@ /* * Copyright (c) 2011 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. */ #ifndef __KIS_RESOURCES_SNAPSHOT_H #define __KIS_RESOURCES_SNAPSHOT_H #include "kis_shared.h" #include "kis_shared_ptr.h" #include "kis_types.h" #include "kritaui_export.h" #include "kis_painter.h" #include "kis_default_bounds.h" class KoCanvasResourceProvider; class KoCompositeOp; class KisPainter; class KisPostExecutionUndoAdapter; class KoPattern; /** * @brief The KisResourcesSnapshot class takes a snapshot of the various resources * like colors and settings used at the begin of a stroke so subsequent * changes don't impact the running stroke. The main reason for the snapshot is that the * user can *change* the options while the stroke is being executed in the background. */ class KRITAUI_EXPORT KisResourcesSnapshot : public KisShared { public: KisResourcesSnapshot(KisImageSP image, KisNodeSP currentNode, KoCanvasResourceProvider *resourceManager, KisDefaultBoundsBaseSP bounds = 0); KisResourcesSnapshot(KisImageSP image, KisNodeSP currentNode, KisDefaultBoundsBaseSP bounds = 0); ~KisResourcesSnapshot(); void setupPainter(KisPainter *painter); void setupMaskingBrushPainter(KisPainter *painter); KisPostExecutionUndoAdapter* postExecutionUndoAdapter() const; void setCurrentNode(KisNodeSP node); void setStrokeStyle(KisPainter::StrokeStyle strokeStyle); void setFillStyle(KisPainter::FillStyle fillStyle); KisNodeSP currentNode() const; KisImageSP image() const; bool needsIndirectPainting() const; QString indirectPaintingCompositeOp() const; bool needsMaskingBrushRendering() const; /** * \return currently active selection. Note that it will return * null if current node *is* the current selection. This * is done to avoid recursive selection application when * painting on selectgion masks. */ KisSelectionSP activeSelection() const; bool needsAirbrushing() const; qreal airbrushingInterval() const; bool needsSpacingUpdates() const; void setOpacity(qreal opacity); quint8 opacity() const; const KoCompositeOp* compositeOp() const; QString compositeOpId() const; - KoPattern* currentPattern() const; + KoPatternSP currentPattern() const; KoColor currentFgColor() const; KoColor currentBgColor() const; KisPaintOpPresetSP currentPaintOpPreset() const; /// @return the channel lock flags of the current node with the global override applied QBitArray channelLockFlags() const; qreal effectiveZoom() const; bool presetAllowsLod() const; bool presetNeedsAsynchronousUpdates() const; void setFGColorOverride(const KoColor &color); void setBGColorOverride(const KoColor &color); void setSelectionOverride(KisSelectionSP selection); void setBrush(const KisPaintOpPresetSP &brush); private: struct Private; Private * const m_d; }; typedef KisSharedPtr KisResourcesSnapshotSP; #endif /* __KIS_RESOURCES_SNAPSHOT_H */ diff --git a/libs/ui/tool/kis_tool.cc b/libs/ui/tool/kis_tool.cc index 4c3bc11e86..827e592733 100644 --- a/libs/ui/tool/kis_tool.cc +++ b/libs/ui/tool/kis_tool.cc @@ -1,709 +1,709 @@ /* * Copyright (c) 2006, 2010 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_tool.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_node_manager.h" #include #include #include #include #include #include #include #include #include #include #include #include "opengl/kis_opengl_canvas2.h" #include "kis_canvas_resource_provider.h" #include "canvas/kis_canvas2.h" #include "kis_coordinates_converter.h" #include "filter/kis_filter_configuration.h" #include "kis_config.h" #include "kis_config_notifier.h" #include "kis_cursor.h" #include #include "kis_resources_snapshot.h" #include #include "kis_action_registry.h" #include "kis_tool_utils.h" struct Q_DECL_HIDDEN KisTool::Private { QCursor cursor; // the cursor that should be shown on tool activation. // From the canvas resources - KoPattern* currentPattern{0}; - KoAbstractGradient* currentGradient{0}; + KoPatternSP currentPattern; + KoAbstractGradientSP currentGradient; KoColor currentFgColor; KoColor currentBgColor; float currentExposure{1.0}; KisFilterConfigurationSP currentGenerator; QWidget* optionWidget{0}; ToolMode m_mode{HOVER_MODE}; bool m_isActive{false}; }; KisTool::KisTool(KoCanvasBase * canvas, const QCursor & cursor) : KoToolBase(canvas) , d(new Private) { d->cursor = cursor; connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(resetCursorStyle())); connect(this, SIGNAL(isActiveChanged(bool)), SLOT(resetCursorStyle())); KActionCollection *collection = this->canvas()->canvasController()->actionCollection(); if (!collection->action("toggle_fg_bg")) { QAction *toggleFgBg = KisActionRegistry::instance()->makeQAction("toggle_fg_bg", collection); collection->addAction("toggle_fg_bg", toggleFgBg); } if (!collection->action("reset_fg_bg")) { QAction *toggleFgBg = KisActionRegistry::instance()->makeQAction("reset_fg_bg", collection); collection->addAction("reset_fg_bg", toggleFgBg); } addAction("toggle_fg_bg", dynamic_cast(collection->action("toggle_fg_bg"))); addAction("reset_fg_bg", dynamic_cast(collection->action("reset_fg_bg"))); } KisTool::~KisTool() { delete d; } void KisTool::activate(ToolActivation activation, const QSet &shapes) { KoToolBase::activate(activation, shapes); resetCursorStyle(); if (!canvas()) return; if (!canvas()->resourceManager()) return; d->currentFgColor = canvas()->resourceManager()->resource(KoCanvasResourceProvider::ForegroundColor).value(); d->currentBgColor = canvas()->resourceManager()->resource(KoCanvasResourceProvider::BackgroundColor).value(); if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::CurrentPattern)) { - d->currentPattern = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPattern).value(); + d->currentPattern = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPattern).value(); } if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::CurrentGradient)) { - d->currentGradient = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentGradient).value(); + d->currentGradient = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentGradient).value(); } KisPaintOpPresetSP preset = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value(); if (preset && preset->settings()) { preset->settings()->activate(); } if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::HdrExposure)) { d->currentExposure = static_cast(canvas()->resourceManager()->resource(KisCanvasResourceProvider::HdrExposure).toDouble()); } if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::CurrentGeneratorConfiguration)) { d->currentGenerator = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentGeneratorConfiguration).value(); } connect(action("toggle_fg_bg"), SIGNAL(triggered()), SLOT(slotToggleFgBg()), Qt::UniqueConnection); connect(action("reset_fg_bg"), SIGNAL(triggered()), SLOT(slotResetFgBg()), Qt::UniqueConnection); d->m_isActive = true; emit isActiveChanged(true); } void KisTool::deactivate() { bool result = true; result &= disconnect(action("toggle_fg_bg"), 0, this, 0); result &= disconnect(action("reset_fg_bg"), 0, this, 0); if (!result) { warnKrita << "WARNING: KisTool::deactivate() failed to disconnect" << "some signal connections. Your actions might be executed twice!"; } d->m_isActive = false; emit isActiveChanged(false); KoToolBase::deactivate(); } void KisTool::canvasResourceChanged(int key, const QVariant & v) { QString formattedBrushName; if (key == KisCanvasResourceProvider::CurrentPaintOpPreset) { formattedBrushName = v.value()->name().replace("_", " "); } switch (key) { case(KoCanvasResourceProvider::ForegroundColor): d->currentFgColor = v.value(); break; case(KoCanvasResourceProvider::BackgroundColor): d->currentBgColor = v.value(); break; case(KisCanvasResourceProvider::CurrentPattern): - d->currentPattern = static_cast(v.value()); + d->currentPattern = v.value(); break; case(KisCanvasResourceProvider::CurrentGradient): - d->currentGradient = static_cast(v.value()); + d->currentGradient = v.value(); break; case(KisCanvasResourceProvider::HdrExposure): d->currentExposure = static_cast(v.toDouble()); break; case(KisCanvasResourceProvider::CurrentGeneratorConfiguration): d->currentGenerator = static_cast(v.value()); break; case(KisCanvasResourceProvider::CurrentPaintOpPreset): emit statusTextChanged(formattedBrushName); break; case(KisCanvasResourceProvider::CurrentKritaNode): resetCursorStyle(); break; default: break; // Do nothing }; } void KisTool::updateSettingsViews() { } QPointF KisTool::widgetCenterInWidgetPixels() { KisCanvas2 *kritaCanvas = dynamic_cast(canvas()); Q_ASSERT(kritaCanvas); const KisCoordinatesConverter *converter = kritaCanvas->coordinatesConverter(); return converter->flakeToWidget(converter->flakeCenterPoint()); } QPointF KisTool::convertDocumentToWidget(const QPointF& pt) { KisCanvas2 *kritaCanvas = dynamic_cast(canvas()); Q_ASSERT(kritaCanvas); return kritaCanvas->coordinatesConverter()->documentToWidget(pt); } QPointF KisTool::convertToPixelCoord(KoPointerEvent *e) { if (!image()) return e->point; return image()->documentToPixel(e->point); } QPointF KisTool::convertToPixelCoord(const QPointF& pt) { if (!image()) return pt; return image()->documentToPixel(pt); } QPointF KisTool::convertToPixelCoordAndSnap(KoPointerEvent *e, const QPointF &offset, bool useModifiers) { if (!image()) return e->point; KoSnapGuide *snapGuide = canvas()->snapGuide(); QPointF pos = snapGuide->snap(e->point, offset, useModifiers ? e->modifiers() : Qt::NoModifier); return image()->documentToPixel(pos); } QPointF KisTool::convertToPixelCoordAndSnap(const QPointF& pt, const QPointF &offset) { if (!image()) return pt; KoSnapGuide *snapGuide = canvas()->snapGuide(); QPointF pos = snapGuide->snap(pt, offset, Qt::NoModifier); return image()->documentToPixel(pos); } QPoint KisTool::convertToImagePixelCoordFloored(KoPointerEvent *e) { if (!image()) return e->point.toPoint(); return image()->documentToImagePixelFloored(e->point); } QPointF KisTool::viewToPixel(const QPointF &viewCoord) const { if (!image()) return viewCoord; return image()->documentToPixel(canvas()->viewConverter()->viewToDocument(viewCoord)); } QRectF KisTool::convertToPt(const QRectF &rect) { if (!image()) return rect; QRectF r; //We add 1 in the following to the extreme coords because a pixel always has size r.setCoords(int(rect.left()) / image()->xRes(), int(rect.top()) / image()->yRes(), int(rect.right()) / image()->xRes(), int( rect.bottom()) / image()->yRes()); return r; } qreal KisTool::convertToPt(qreal value) { const qreal avgResolution = 0.5 * (image()->xRes() + image()->yRes()); return value / avgResolution; } QPointF KisTool::pixelToView(const QPoint &pixelCoord) const { if (!image()) return pixelCoord; QPointF documentCoord = image()->pixelToDocument(pixelCoord); return canvas()->viewConverter()->documentToView(documentCoord); } QPointF KisTool::pixelToView(const QPointF &pixelCoord) const { if (!image()) return pixelCoord; QPointF documentCoord = image()->pixelToDocument(pixelCoord); return canvas()->viewConverter()->documentToView(documentCoord); } QRectF KisTool::pixelToView(const QRectF &pixelRect) const { if (!image()) return pixelRect; QPointF topLeft = pixelToView(pixelRect.topLeft()); QPointF bottomRight = pixelToView(pixelRect.bottomRight()); return QRectF(topLeft, bottomRight); } QPainterPath KisTool::pixelToView(const QPainterPath &pixelPolygon) const { QTransform matrix; qreal zoomX, zoomY; canvas()->viewConverter()->zoom(&zoomX, &zoomY); matrix.scale(zoomX/image()->xRes(), zoomY/ image()->yRes()); return matrix.map(pixelPolygon); } QPolygonF KisTool::pixelToView(const QPolygonF &pixelPath) const { QTransform matrix; qreal zoomX, zoomY; canvas()->viewConverter()->zoom(&zoomX, &zoomY); matrix.scale(zoomX/image()->xRes(), zoomY/ image()->yRes()); return matrix.map(pixelPath); } void KisTool::updateCanvasPixelRect(const QRectF &pixelRect) { canvas()->updateCanvas(convertToPt(pixelRect)); } void KisTool::updateCanvasViewRect(const QRectF &viewRect) { canvas()->updateCanvas(canvas()->viewConverter()->viewToDocument(viewRect)); } KisImageWSP KisTool::image() const { // For now, krita tools only work in krita, not for a krita shape. Krita shapes are for 2.1 KisCanvas2 * kisCanvas = dynamic_cast(canvas()); if (kisCanvas) { return kisCanvas->currentImage(); } return 0; } QCursor KisTool::cursor() const { return d->cursor; } void KisTool::notifyModified() const { if (image()) { image()->setModified(); } } -KoPattern * KisTool::currentPattern() +KoPatternSP KisTool::currentPattern() { return d->currentPattern; } -KoAbstractGradient * KisTool::currentGradient() +KoAbstractGradientSP KisTool::currentGradient() { return d->currentGradient; } KisPaintOpPresetSP KisTool::currentPaintOpPreset() { return canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value(); } KisNodeSP KisTool::currentNode() const { KisNodeSP node = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentKritaNode).value(); return node; } KisNodeList KisTool::selectedNodes() const { KisCanvas2 * kiscanvas = static_cast(canvas()); KisViewManager* viewManager = kiscanvas->viewManager(); return viewManager->nodeManager()->selectedNodes(); } KoColor KisTool::currentFgColor() { return d->currentFgColor; } KoColor KisTool::currentBgColor() { return d->currentBgColor; } KisImageWSP KisTool::currentImage() { return image(); } KisFilterConfigurationSP KisTool::currentGenerator() { return d->currentGenerator; } void KisTool::setMode(ToolMode mode) { d->m_mode = mode; } KisTool::ToolMode KisTool::mode() const { return d->m_mode; } void KisTool::setCursor(const QCursor &cursor) { d->cursor = cursor; } KisTool::AlternateAction KisTool::actionToAlternateAction(ToolAction action) { KIS_ASSERT_RECOVER_RETURN_VALUE(action != Primary, Secondary); return (AlternateAction)action; } void KisTool::activatePrimaryAction() { resetCursorStyle(); } void KisTool::deactivatePrimaryAction() { resetCursorStyle(); } void KisTool::beginPrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::beginPrimaryDoubleClickAction(KoPointerEvent *event) { beginPrimaryAction(event); } void KisTool::continuePrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::endPrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); } bool KisTool::primaryActionSupportsHiResEvents() const { return false; } void KisTool::activateAlternateAction(AlternateAction action) { Q_UNUSED(action); } void KisTool::deactivateAlternateAction(AlternateAction action) { Q_UNUSED(action); } void KisTool::beginAlternateAction(KoPointerEvent *event, AlternateAction action) { Q_UNUSED(event); Q_UNUSED(action); } void KisTool::beginAlternateDoubleClickAction(KoPointerEvent *event, AlternateAction action) { beginAlternateAction(event, action); } void KisTool::continueAlternateAction(KoPointerEvent *event, AlternateAction action) { Q_UNUSED(event); Q_UNUSED(action); } void KisTool::endAlternateAction(KoPointerEvent *event, AlternateAction action) { Q_UNUSED(event); Q_UNUSED(action); } void KisTool::mouseDoubleClickEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::mouseTripleClickEvent(KoPointerEvent *event) { mouseDoubleClickEvent(event); } void KisTool::mousePressEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::mouseReleaseEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::mouseMoveEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::deleteSelection() { KisResourcesSnapshotSP resources = new KisResourcesSnapshot(image(), currentNode(), this->canvas()->resourceManager()); if (!blockUntilOperationsFinished()) { return; } if (!KisToolUtils::clearImage(image(), resources->currentNode(), resources->activeSelection())) { KoToolBase::deleteSelection(); } } QWidget* KisTool::createOptionWidget() { d->optionWidget = new QLabel(i18n("No options")); d->optionWidget->setObjectName("SpecialSpacer"); return d->optionWidget; } #define NEAR_VAL -1000.0 #define FAR_VAL 1000.0 #define PROGRAM_VERTEX_ATTRIBUTE 0 void KisTool::paintToolOutline(QPainter* painter, const QPainterPath &path) { KisOpenGLCanvas2 *canvasWidget = dynamic_cast(canvas()->canvasWidget()); if (canvasWidget) { painter->beginNativePainting(); canvasWidget->paintToolOutline(path); painter->endNativePainting(); } else { painter->save(); painter->setCompositionMode(QPainter::RasterOp_SourceXorDestination); painter->setPen(QColor(128, 255, 128)); painter->drawPath(path); painter->restore(); } } void KisTool::resetCursorStyle() { useCursor(d->cursor); } bool KisTool::overrideCursorIfNotEditable() { // override cursor for canvas iff this tool is active // and we can't paint on the active layer if (isActive()) { KisNodeSP node = currentNode(); if (node && !node->isEditable()) { canvas()->setCursor(Qt::ForbiddenCursor); return true; } } return false; } bool KisTool::blockUntilOperationsFinished() { KisCanvas2 * kiscanvas = static_cast(canvas()); KisViewManager* viewManager = kiscanvas->viewManager(); return viewManager->blockUntilOperationsFinished(image()); } void KisTool::blockUntilOperationsFinishedForced() { KisCanvas2 * kiscanvas = static_cast(canvas()); KisViewManager* viewManager = kiscanvas->viewManager(); viewManager->blockUntilOperationsFinishedForced(image()); } bool KisTool::isActive() const { return d->m_isActive; } void KisTool::slotToggleFgBg() { KoCanvasResourceProvider* resourceManager = canvas()->resourceManager(); KoColor newFg = resourceManager->backgroundColor(); KoColor newBg = resourceManager->foregroundColor(); /** * NOTE: Some of color selectors do not differentiate foreground * and background colors, so if one wants them to end up * being set up to foreground color, it should be set the * last. */ resourceManager->setBackgroundColor(newBg); resourceManager->setForegroundColor(newFg); } void KisTool::slotResetFgBg() { KoCanvasResourceProvider* resourceManager = canvas()->resourceManager(); // see a comment in slotToggleFgBg() resourceManager->setBackgroundColor(KoColor(Qt::white, KoColorSpaceRegistry::instance()->rgb8())); resourceManager->setForegroundColor(KoColor(Qt::black, KoColorSpaceRegistry::instance()->rgb8())); } bool KisTool::nodeEditable() { KisNodeSP node = currentNode(); if (!node) { return false; } bool blockedNoIndirectPainting = false; const bool presetUsesIndirectPainting = !currentPaintOpPreset()->settings()->paintIncremental(); if (!presetUsesIndirectPainting) { const KisIndirectPaintingSupport *indirectPaintingLayer = dynamic_cast(node.data()); if (indirectPaintingLayer) { blockedNoIndirectPainting = !indirectPaintingLayer->supportsNonIndirectPainting(); } } bool nodeEditable = node->isEditable() && !blockedNoIndirectPainting; if (!nodeEditable) { KisCanvas2 * kiscanvas = static_cast(canvas()); QString message; if (!node->visible() && node->userLocked()) { message = i18n("Layer is locked and invisible."); } else if (node->userLocked()) { message = i18n("Layer is locked."); } else if(!node->visible()) { message = i18n("Layer is invisible."); } else if (blockedNoIndirectPainting) { message = i18n("Layer can be painted in Wash Mode only."); } else { message = i18n("Group not editable."); } kiscanvas->viewManager()->showFloatingMessage(message, KisIconUtils::loadIcon("object-locked")); } return nodeEditable; } bool KisTool::selectionEditable() { KisCanvas2 * kisCanvas = static_cast(canvas()); KisViewManager * view = kisCanvas->viewManager(); bool editable = view->selectionEditable(); if (!editable) { KisCanvas2 * kiscanvas = static_cast(canvas()); kiscanvas->viewManager()->showFloatingMessage(i18n("Local selection is locked."), KisIconUtils::loadIcon("object-locked")); } return editable; } void KisTool::listenToModifiers(bool listen) { Q_UNUSED(listen); } bool KisTool::listeningToModifiers() { return false; } diff --git a/libs/ui/tool/kis_tool.h b/libs/ui/tool/kis_tool.h index 83eb6ede95..f8aba280b9 100644 --- a/libs/ui/tool/kis_tool.h +++ b/libs/ui/tool/kis_tool.h @@ -1,322 +1,322 @@ /* * 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. */ #ifndef KIS_TOOL_H_ #define KIS_TOOL_H_ #include #include #include #include #include -#include +#include +#include + #include #ifdef __GNUC__ #define WARN_WRONG_MODE(_mode) warnKrita << "Unexpected tool event has come to" << __func__ << "while being mode" << _mode << "!" #else #define WARN_WRONG_MODE(_mode) warnKrita << "Unexpected tool event has come while being mode" << _mode << "!" #endif #define CHECK_MODE_SANITY_OR_RETURN(_mode) if (mode() != _mode) { WARN_WRONG_MODE(mode()); return; } class KoCanvasBase; -class KoPattern; -class KoAbstractGradient; class KisFilterConfiguration; class QPainter; class QPainterPath; class QPolygonF; /// Definitions of the toolgroups of Krita static const QString TOOL_TYPE_SHAPE = "0 Krita/Shape"; // Geometric shapes like ellipses and lines static const QString TOOL_TYPE_TRANSFORM = "2 Krita/Transform"; // Tools that transform the layer; static const QString TOOL_TYPE_FILL = "3 Krita/Fill"; // Tools that fill parts of the canvas static const QString TOOL_TYPE_VIEW = "4 Krita/View"; // Tools that affect the canvas: pan, zoom, etc. static const QString TOOL_TYPE_SELECTION = "5 Krita/Select"; // Tools that select pixels //activation id for Krita tools, Krita tools are always active and handle locked and invisible layers by themself static const QString KRITA_TOOL_ACTIVATION_ID = "flake/always"; -class KRITAUI_EXPORT KisTool - : public KoToolBase +#include +class KRITAUI_EXPORT KisTool : public KoToolBase { Q_OBJECT Q_PROPERTY(bool isActive READ isActive NOTIFY isActiveChanged) public: enum { FLAG_USES_CUSTOM_PRESET=0x01, FLAG_USES_CUSTOM_COMPOSITEOP=0x02, FLAG_USES_CUSTOM_SIZE=0x04 }; KisTool(KoCanvasBase * canvas, const QCursor & cursor); ~KisTool() override; virtual int flags() const { return 0; } void deleteSelection() override; // KoToolBase Implementation. public: /** * Called by KisToolProxy when the primary action of the tool is * going to be started now, that is when all the modifiers are * pressed and the only thing left is just to press the mouse * button. On coming of this callback the tool is supposed to * prepare the cursor and/or the outline to show the user shat is * going to happen next */ virtual void activatePrimaryAction(); /** * Called by KisToolProxy when the primary is no longer possible * to be started now, e.g. when its modifiers and released. The * tool is supposed revert all the preparetions it has doen in * activatePrimaryAction(). */ virtual void deactivatePrimaryAction(); /** * Called by KisToolProxy when a primary action for the tool is * started. The \p event stores the original event that * started the stroke. The \p event is _accepted_ by default. If * the tool decides to ignore this particular action (e.g. when * the node is not editable), it should call event->ignore(). Then * no further continuePrimaryAction() or endPrimaryAction() will * be called until the next user action. */ virtual void beginPrimaryAction(KoPointerEvent *event); /** * Called by KisToolProxy when the primary action is in progress * of pointer movement. If the tool has ignored the event in * beginPrimaryAction(), this method will not be called. */ virtual void continuePrimaryAction(KoPointerEvent *event); /** * Called by KisToolProxy when the primary action is being * finished, that is while mouseRelease or tabletRelease event. * If the tool has ignored the event in beginPrimaryAction(), this * method will not be called. */ virtual void endPrimaryAction(KoPointerEvent *event); /** * The same as beginPrimaryAction(), but called when the stroke is * started by a double-click * * \see beginPrimaryAction() */ virtual void beginPrimaryDoubleClickAction(KoPointerEvent *event); /** * Returns true if the tool can handle (and wants to handle) a * very tight flow of input events from the tablet */ virtual bool primaryActionSupportsHiResEvents() const; enum ToolAction { Primary, AlternateChangeSize, AlternatePickFgNode, AlternatePickBgNode, AlternatePickFgImage, AlternatePickBgImage, AlternateSecondary, AlternateThird, AlternateFourth, AlternateFifth, Alternate_NONE = 10000 }; // Technically users are allowed to configure this, but nobody ever would do that. // So these can basically be thought of as aliases to ctrl+click, etc. enum AlternateAction { ChangeSize = AlternateChangeSize, // Default: Shift+Left click PickFgNode = AlternatePickFgNode, // Default: Ctrl+Alt+Left click PickBgNode = AlternatePickBgNode, // Default: Ctrl+Alt+Right click PickFgImage = AlternatePickFgImage, // Default: Ctrl+Left click PickBgImage = AlternatePickBgImage, // Default: Ctrl+Right click Secondary = AlternateSecondary, Third = AlternateThird, Fourth = AlternateFourth, Fifth = AlternateFifth, NONE = 10000 }; static AlternateAction actionToAlternateAction(ToolAction action); virtual void activateAlternateAction(AlternateAction action); virtual void deactivateAlternateAction(AlternateAction action); virtual void beginAlternateAction(KoPointerEvent *event, AlternateAction action); virtual void continueAlternateAction(KoPointerEvent *event, AlternateAction action); virtual void endAlternateAction(KoPointerEvent *event, AlternateAction action); virtual void beginAlternateDoubleClickAction(KoPointerEvent *event, AlternateAction action); void mousePressEvent(KoPointerEvent *event) override; void mouseDoubleClickEvent(KoPointerEvent *event) override; void mouseTripleClickEvent(KoPointerEvent *event) override; void mouseReleaseEvent(KoPointerEvent *event) override; void mouseMoveEvent(KoPointerEvent *event) override; bool isActive() const; public Q_SLOTS: void activate(ToolActivation activation, const QSet &shapes) override; void deactivate() override; void canvasResourceChanged(int key, const QVariant & res) override; // Implement this slot in case there are any widgets or properties which need // to be updated after certain operations, to reflect the inner state correctly. // At the moment this is used for smoothing options in the freehand brush, but // this will likely be expanded. virtual void updateSettingsViews(); Q_SIGNALS: void isActiveChanged(bool isActivated); protected: // conversion methods are also needed by the paint information builder friend class KisToolPaintingInformationBuilder; /// Convert from native (postscript points) to image pixel /// coordinates. QPointF convertToPixelCoord(KoPointerEvent *e); QPointF convertToPixelCoord(const QPointF& pt); QPointF convertToPixelCoordAndSnap(KoPointerEvent *e, const QPointF &offset = QPointF(), bool useModifiers = true); QPointF convertToPixelCoordAndSnap(const QPointF& pt, const QPointF &offset = QPointF()); protected: QPointF widgetCenterInWidgetPixels(); QPointF convertDocumentToWidget(const QPointF& pt); /// Convert from native (postscript points) to integer image pixel /// coordinates. This rounds down (not truncate) the pixel coordinates and /// should be used in preference to QPointF::toPoint(), which rounds, /// to ensure the cursor acts on the pixel it is visually over. QPoint convertToImagePixelCoordFloored(KoPointerEvent *e); QRectF convertToPt(const QRectF &rect); qreal convertToPt(qreal value); QPointF viewToPixel(const QPointF &viewCoord) const; /// Convert an integer pixel coordinate into a view coordinate. /// The view coordinate is at the centre of the pixel. QPointF pixelToView(const QPoint &pixelCoord) const; /// Convert a floating point pixel coordinate into a view coordinate. QPointF pixelToView(const QPointF &pixelCoord) const; /// Convert a pixel rectangle into a view rectangle. QRectF pixelToView(const QRectF &pixelRect) const; /// Convert a pixel path into a view path QPainterPath pixelToView(const QPainterPath &pixelPath) const; /// Convert a pixel polygon into a view path QPolygonF pixelToView(const QPolygonF &pixelPolygon) const; /// Update the canvas for the given rectangle in image pixel coordinates. void updateCanvasPixelRect(const QRectF &pixelRect); /// Update the canvas for the given rectangle in view coordinates. void updateCanvasViewRect(const QRectF &viewRect); QWidget* createOptionWidget() override; /** * To determine whether this tool will change its behavior when * modifier keys are pressed */ virtual bool listeningToModifiers(); /** * Request that this tool no longer listen to modifier keys * (Responding to the request is optional) */ virtual void listenToModifiers(bool listen); protected: KisImageWSP image() const; QCursor cursor() const; /// Call this to set the document modified void notifyModified() const; KisImageWSP currentImage(); - KoPattern* currentPattern(); - KoAbstractGradient *currentGradient(); + KoPatternSP currentPattern(); + KoAbstractGradientSP currentGradient(); KisNodeSP currentNode() const; KisNodeList selectedNodes() const; KoColor currentFgColor(); KoColor currentBgColor(); KisPaintOpPresetSP currentPaintOpPreset(); KisFilterConfigurationSP currentGenerator(); /// paint the path which is in view coordinates, default paint mode is XOR_MODE, BW_MODE is also possible /// never apply transformations to the painter, they would be useless, if drawing in OpenGL mode. The coordinates in the path should be in view coordinates. void paintToolOutline(QPainter * painter, const QPainterPath &path); /// Checks checks if the current node is editable bool nodeEditable(); /// Checks checks if the selection is editable, only applies to local selection as global selection is always editable bool selectionEditable(); /// Override the cursor appropriately if current node is not editable bool overrideCursorIfNotEditable(); bool blockUntilOperationsFinished(); void blockUntilOperationsFinishedForced(); protected: enum ToolMode { HOVER_MODE, PAINT_MODE, SECONDARY_PAINT_MODE, MIRROR_AXIS_SETUP_MODE, GESTURE_MODE, PAN_MODE, OTHER // not used now }; virtual void setMode(ToolMode mode); virtual ToolMode mode() const; void setCursor(const QCursor &cursor); protected Q_SLOTS: /** * Called whenever the configuration settings change. */ virtual void resetCursorStyle(); private Q_SLOTS: void slotToggleFgBg(); void slotResetFgBg(); private: struct Private; Private* const d; }; #endif // KIS_TOOL_H_ diff --git a/libs/ui/tool/strokes/KisMaskedFreehandStrokePainter.h b/libs/ui/tool/strokes/KisMaskedFreehandStrokePainter.h index 3957876577..99e4e4d7ad 100644 --- a/libs/ui/tool/strokes/KisMaskedFreehandStrokePainter.h +++ b/libs/ui/tool/strokes/KisMaskedFreehandStrokePainter.h @@ -1,90 +1,89 @@ /* * Copyright (c) 2017 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. */ #ifndef KISMASKEDPAINTINGSTROKEDATA_H #define KISMASKEDPAINTINGSTROKEDATA_H #include "kritaui_export.h" #include +#include class KisFreehandStrokeInfo; class KisPaintInformation; class KisDistanceInformation; class QPointF; class QRectF; class QRect; class QPainterPath; class QPen; class KoColor; class KisRunnableStrokeJobData; class KisPaintOpPreset; -template -class KisSharedPtr; -typedef KisSharedPtr KisPaintOpPresetSP; +typedef QSharedPointer KisPaintOpPresetSP; class KRITAUI_EXPORT KisMaskedFreehandStrokePainter { public: KisMaskedFreehandStrokePainter(KisFreehandStrokeInfo *strokeData, KisFreehandStrokeInfo *maskData); // painter overrides KisPaintOpPresetSP preset() const; void paintAt(const KisPaintInformation& pi); void paintLine(const KisPaintInformation &pi1, const KisPaintInformation &pi2); void paintBezierCurve(const KisPaintInformation &pi1, const QPointF &control1, const QPointF &control2, const KisPaintInformation &pi2); void paintPolyline(const QVector &points, int index = 0, int numPoints = -1); void paintPolygon(const QVector &points); void paintRect(const QRectF &rect); void paintEllipse(const QRectF &rect); void paintPainterPath(const QPainterPath& path); void drawPainterPath(const QPainterPath& path, const QPen& pen); void drawAndFillPainterPath(const QPainterPath& path, const QPen& pen, const KoColor &customColor); // paintop overrides std::pair doAsyncronousUpdate(QVector &jobs); bool hasDirtyRegion() const; QVector takeDirtyRegion(); bool hasMasking() const; private: template inline void applyToAllPainters(Func func); private: KisFreehandStrokeInfo *m_stroke = 0; KisFreehandStrokeInfo *m_mask = 0; }; #endif // KISMASKEDPAINTINGSTROKEDATA_H diff --git a/libs/ui/widgets/KisGamutMaskToolbar.cpp b/libs/ui/widgets/KisGamutMaskToolbar.cpp index 88201939b3..5eeb239fcf 100644 --- a/libs/ui/widgets/KisGamutMaskToolbar.cpp +++ b/libs/ui/widgets/KisGamutMaskToolbar.cpp @@ -1,115 +1,115 @@ /* * Copyright (c) 2018 Anna Medonosova * * 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; version 2.1 of the License. * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "KisGamutMaskToolbar.h" #include #include KisGamutMaskToolbar::KisGamutMaskToolbar(QWidget* parent) : QWidget(parent) , m_selectedMask(nullptr) { m_ui = new Ui_wdgGamutMaskToolbar(); m_ui->setupUi(this); m_iconMaskOff = KisIconUtils::loadIcon("gamut-mask-off"); m_iconMaskOn = KisIconUtils::loadIcon("gamut-mask-on"); m_textNoMask = i18n("Select a mask in \"Gamut Masks\" docker"); m_textMaskDisabled = i18n("Mask is disabled"); m_ui->bnToggleMask->setChecked(false); m_ui->bnToggleMask->setIcon(m_iconMaskOff); m_ui->rotationSlider->setRange(0, 360); m_ui->rotationSlider->setPrefix(i18n("Rotation: ")); m_ui->rotationSlider->setSuffix("°"); m_ui->rotationSlider->setFastSliderStep(30); // TODO: test for usability m_ui->rotationSlider->hide(); // gamut mask connections connect(m_ui->bnToggleMask, SIGNAL(toggled(bool)), SLOT(slotGamutMaskToggle(bool))); connect(m_ui->rotationSlider, SIGNAL(valueChanged(int)), SLOT(slotGamutMaskRotate(int))); } void KisGamutMaskToolbar::connectMaskSignals(KisCanvasResourceProvider* resourceProvider) { - connect(resourceProvider, SIGNAL(sigGamutMaskChanged(KoGamutMask*)), - this, SLOT(slotGamutMaskSet(KoGamutMask*))); + connect(resourceProvider, SIGNAL(sigGamutMaskChanged(KoGamutMaskSP)), + this, SLOT(slotGamutMaskSet(KoGamutMaskSP))); connect(resourceProvider, SIGNAL(sigGamutMaskUnset()), this, SLOT(slotGamutMaskUnset())); - connect(this, SIGNAL(sigGamutMaskChanged(KoGamutMask*)), - resourceProvider, SLOT(slotGamutMaskActivated(KoGamutMask*))); + connect(this, SIGNAL(sigGamutMaskChanged(KoGamutMaskSP)), + resourceProvider, SLOT(slotGamutMaskActivated(KoGamutMaskSP))); } -void KisGamutMaskToolbar::slotGamutMaskSet(KoGamutMask *mask) +void KisGamutMaskToolbar::slotGamutMaskSet(KoGamutMaskSP mask) { if (!mask) { return; } m_selectedMask = mask; if (m_selectedMask) { slotGamutMaskToggle(true); } else { slotGamutMaskToggle(false); } } void KisGamutMaskToolbar::slotGamutMaskUnset() { m_ui->rotationSlider->hide(); m_ui->labelMaskName->show(); m_ui->labelMaskName->setText(m_textNoMask); } void KisGamutMaskToolbar::slotGamutMaskToggle(bool state) { bool b = (!m_selectedMask) ? false : state; m_ui->bnToggleMask->setChecked(b); if (b == true) { m_ui->bnToggleMask->setIcon(m_iconMaskOn); m_ui->labelMaskName->hide(); m_ui->rotationSlider->show(); m_ui->rotationSlider->blockSignals(true); m_ui->rotationSlider->setValue(m_selectedMask->rotation()); m_ui->rotationSlider->blockSignals(false); } else { m_ui->bnToggleMask->setIcon(m_iconMaskOff); m_ui->rotationSlider->hide(); m_ui->labelMaskName->show(); m_ui->labelMaskName->setText(m_textMaskDisabled); } emit sigGamutMaskToggle(state); } void KisGamutMaskToolbar::slotGamutMaskRotate(int angle) { if (!m_selectedMask) { return; } m_selectedMask->setRotation(angle); emit sigGamutMaskChanged(m_selectedMask); } diff --git a/libs/ui/widgets/KisGamutMaskToolbar.h b/libs/ui/widgets/KisGamutMaskToolbar.h index 45386705b2..da08ab5817 100644 --- a/libs/ui/widgets/KisGamutMaskToolbar.h +++ b/libs/ui/widgets/KisGamutMaskToolbar.h @@ -1,61 +1,61 @@ /* * Copyright (c) 2018 Anna Medonosova * * 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; version 2.1 of the License. * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KISGAMUTMASKTOOLBAR_H #define KISGAMUTMASKTOOLBAR_H #include #include #include #include "kritaui_export.h" #include "ui_wdgGamutMaskToolbar.h" class KisCanvasResourceProvider; class KRITAUI_EXPORT KisGamutMaskToolbar : public QWidget { Q_OBJECT public: KisGamutMaskToolbar(QWidget* parent = nullptr); void connectMaskSignals(KisCanvasResourceProvider* resourceProvider); Q_SIGNALS: void sigGamutMaskToggle(bool state); - void sigGamutMaskChanged(KoGamutMask*); + void sigGamutMaskChanged(KoGamutMaskSP); public Q_SLOTS: - void slotGamutMaskSet(KoGamutMask* mask); + void slotGamutMaskSet(KoGamutMaskSP mask); void slotGamutMaskUnset(); private Q_SLOTS: void slotGamutMaskToggle(bool state); void slotGamutMaskRotate(int angle); private: Ui_wdgGamutMaskToolbar* m_ui; - KoGamutMask* m_selectedMask; + KoGamutMaskSP m_selectedMask; QIcon m_iconMaskOff; QIcon m_iconMaskOn; QString m_textNoMask; QString m_textMaskDisabled; }; #endif // KISGAMUTMASKTOOLBAR_H diff --git a/libs/ui/widgets/KoFillConfigWidget.cpp b/libs/ui/widgets/KoFillConfigWidget.cpp index 6b2adb8a8e..20f25c8e1e 100644 --- a/libs/ui/widgets/KoFillConfigWidget.cpp +++ b/libs/ui/widgets/KoFillConfigWidget.cpp @@ -1,851 +1,851 @@ /* This file is part of the KDE project * Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) * Copyright (C) 2012 Jean-Nicolas Artaud * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoFillConfigWidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KoResourceServerProvider.h" #include "KoResourceServerAdapter.h" #include "KoResourceSelector.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KoZoomHandler.h" #include "KoColorPopupButton.h" #include "ui_KoFillConfigWidget.h" #include #include #include #include #include "kis_canvas_resource_provider.h" #include #include #include #include "kis_global.h" #include "kis_debug.h" static const char* const buttonnone[]={ "16 16 3 1", "# c #000000", "e c #ff0000", "- c #ffffff", "################", "#--------------#", "#-e----------e-#", "#--e--------e--#", "#---e------e---#", "#----e----e----#", "#-----e--e-----#", "#------ee------#", "#------ee------#", "#-----e--e-----#", "#----e----e----#", "#---e------e---#", "#--e--------e--#", "#-e----------e-#", "#--------------#", "################"}; static const char* const buttonsolid[]={ "16 16 2 1", "# c #000000", ". c #969696", "################", "#..............#", "#..............#", "#..............#", "#..............#", "#..............#", "#..............#", "#..............#", "#..............#", "#..............#", "#..............#", "#..............#", "#..............#", "#..............#", "#..............#", "################"}; // FIXME: Smoother gradient button. static const char* const buttongradient[]={ "16 16 15 1", "# c #000000", "n c #101010", "m c #202020", "l c #303030", "k c #404040", "j c #505050", "i c #606060", "h c #707070", "g c #808080", "f c #909090", "e c #a0a0a0", "d c #b0b0b0", "c c #c0c0c0", "b c #d0d0d0", "a c #e0e0e0", "################", "#abcdefghijklmn#", "#abcdefghijklmn#", "#abcdefghijklmn#", "#abcdefghijklmn#", "#abcdefghijklmn#", "#abcdefghijklmn#", "#abcdefghijklmn#", "#abcdefghijklmn#", "#abcdefghijklmn#", "#abcdefghijklmn#", "#abcdefghijklmn#", "#abcdefghijklmn#", "#abcdefghijklmn#", "#abcdefghijklmn#", "################"}; static const char* const buttonpattern[]={ "16 16 4 1", ". c #0a0a0a", "# c #333333", "a c #a0a0a0", "b c #ffffffff", "################", "#aaaaabbbbaaaaa#", "#aaaaabbbbaaaaa#", "#aaaaabbbbaaaaa#", "#aaaaabbbbaaaaa#", "#aaaaabbbbaaaaa#", "#bbbbbaaaabbbbb#", "#bbbbbaaaabbbbb#", "#bbbbbaaaabbbbb#", "#bbbbbaaaabbbbb#", "#aaaaabbbbaaaaa#", "#aaaaabbbbaaaaa#", "#aaaaabbbbaaaaa#", "#aaaaabbbbaaaaa#", "#aaaaabbbbaaaaa#", "################"}; class Q_DECL_HIDDEN KoFillConfigWidget::Private { public: Private(KoFlake::FillVariant _fillVariant) : canvas(0), colorChangedCompressor(100, KisSignalCompressor::FIRST_ACTIVE), gradientChangedCompressor(100, KisSignalCompressor::FIRST_ACTIVE), fillVariant(_fillVariant), noSelectionTrackingMode(false) { } KoColorPopupAction *colorAction; KoResourcePopupAction *gradientAction; KoResourcePopupAction *patternAction; QButtonGroup *group; KoCanvasBase *canvas; KisSignalCompressor colorChangedCompressor; KisAcyclicSignalConnector shapeChangedAcyclicConnector; KisAcyclicSignalConnector resourceManagerAcyclicConnector; KoFillConfigWidget::StyleButton selectedFillIndex; - QSharedPointer activeGradient; + KoStopGradientSP activeGradient; KisSignalCompressor gradientChangedCompressor; KoFlake::FillVariant fillVariant; bool noSelectionTrackingMode; Ui_KoFillConfigWidget *ui; std::vector deactivationLocks; }; KoFillConfigWidget::KoFillConfigWidget(KoCanvasBase *canvas, KoFlake::FillVariant fillVariant, bool trackShapeSelection, QWidget *parent) : QWidget(parent) , d(new Private(fillVariant)) { d->canvas = canvas; if (trackShapeSelection) { d->shapeChangedAcyclicConnector.connectBackwardVoid( d->canvas->selectedShapesProxy(), SIGNAL(selectionChanged()), this, SLOT(shapeChanged())); d->shapeChangedAcyclicConnector.connectBackwardVoid( d->canvas->selectedShapesProxy(), SIGNAL(selectionContentChanged()), this, SLOT(shapeChanged())); } d->resourceManagerAcyclicConnector.connectBackwardResourcePair( d->canvas->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)), this, SLOT(slotCanvasResourceChanged(int,QVariant))); d->resourceManagerAcyclicConnector.connectForwardVoid( this, SIGNAL(sigInternalRequestColorToResourceManager()), this, SLOT(slotProposeCurrentColorToResourceManager())); // configure GUI d->ui = new Ui_KoFillConfigWidget(); d->ui->setupUi(this); d->group = new QButtonGroup(this); d->group->setExclusive(true); d->ui->btnNoFill->setIcon(QPixmap((const char **) buttonnone)); d->group->addButton(d->ui->btnNoFill, None); d->ui->btnSolidFill->setIcon(QPixmap((const char **) buttonsolid)); d->group->addButton(d->ui->btnSolidFill, Solid); d->ui->btnGradientFill->setIcon(QPixmap((const char **) buttongradient)); d->group->addButton(d->ui->btnGradientFill, Gradient); d->ui->btnPatternFill->setIcon(QPixmap((const char **) buttonpattern)); d->group->addButton(d->ui->btnPatternFill, Pattern); d->colorAction = new KoColorPopupAction(d->ui->btnChooseSolidColor); d->colorAction->setToolTip(i18n("Change the filling color")); d->colorAction->setCurrentColor(Qt::white); d->ui->btnChooseSolidColor->setDefaultAction(d->colorAction); d->ui->btnChooseSolidColor->setPopupMode(QToolButton::InstantPopup); d->ui->btnSolidColorPick->setIcon(KisIconUtils::loadIcon("krita_tool_color_picker")); // TODO: for now the color picking button is disabled! d->ui->btnSolidColorPick->setEnabled(false); d->ui->btnSolidColorPick->setVisible(false); connect(d->colorAction, SIGNAL(colorChanged(KoColor)), &d->colorChangedCompressor, SLOT(start())); connect(&d->colorChangedCompressor, SIGNAL(timeout()), SLOT(colorChanged())); connect(d->ui->btnChooseSolidColor, SIGNAL(iconSizeChanged()), d->colorAction, SLOT(updateIcon())); connect(d->group, SIGNAL(buttonClicked(int)), SLOT(styleButtonPressed(int))); connect(d->group, SIGNAL(buttonClicked(int)), SLOT(slotUpdateFillTitle())); slotUpdateFillTitle(); styleButtonPressed(d->group->checkedId()); // Gradient selector d->ui->wdgGradientEditor->setCompactMode(true); connect(d->ui->wdgGradientEditor, SIGNAL(sigGradientChanged()), &d->gradientChangedCompressor, SLOT(start())); connect(&d->gradientChangedCompressor, SIGNAL(timeout()), SLOT(activeGradientChanged())); KoResourceServerProvider *serverProvider = KoResourceServerProvider::instance(); QSharedPointer gradientResourceAdapter( new KoResourceServerAdapter(serverProvider->gradientServer())); d->gradientAction = new KoResourcePopupAction(gradientResourceAdapter, d->ui->btnChoosePredefinedGradient); d->gradientAction->setToolTip(i18n("Change filling gradient")); d->ui->btnChoosePredefinedGradient->setDefaultAction(d->gradientAction); d->ui->btnChoosePredefinedGradient->setPopupMode(QToolButton::InstantPopup); connect(d->gradientAction, SIGNAL(resourceSelected(QSharedPointer)), SLOT(gradientResourceChanged())); connect(d->ui->btnChoosePredefinedGradient, SIGNAL(iconSizeChanged()), d->gradientAction, SLOT(updateIcon())); d->ui->btnSaveGradient->setIcon(KisIconUtils::loadIcon("document-save")); connect(d->ui->btnSaveGradient, SIGNAL(clicked()), SLOT(slotSavePredefinedGradientClicked())); connect(d->ui->cmbGradientRepeat, SIGNAL(currentIndexChanged(int)), SLOT(slotGradientRepeatChanged())); connect(d->ui->cmbGradientType, SIGNAL(currentIndexChanged(int)), SLOT(slotGradientTypeChanged())); deactivate(); #if 0 // Pattern selector QSharedPointerpatternResourceAdapter(new KoResourceServerAdapter(serverProvider->patternServer())); d->patternAction = new KoResourcePopupAction(patternResourceAdapter, d->colorButton); d->patternAction->setToolTip(i18n("Change the filling pattern")); connect(d->patternAction, SIGNAL(resourceSelected(QSharedPointer)), this, SLOT(patternChanged(QSharedPointer))); connect(d->colorButton, SIGNAL(iconSizeChanged()), d->patternAction, SLOT(updateIcon())); #endif } KoFillConfigWidget::~KoFillConfigWidget() { delete d; } void KoFillConfigWidget::activate() { KIS_SAFE_ASSERT_RECOVER_RETURN(!d->deactivationLocks.empty()); d->deactivationLocks.clear(); if (!d->noSelectionTrackingMode) { shapeChanged(); } else { loadCurrentFillFromResourceServer(); } updateWidgetComponentVisbility(); } void KoFillConfigWidget::deactivate() { KIS_SAFE_ASSERT_RECOVER_RETURN(d->deactivationLocks.empty()); d->deactivationLocks.push_back(KisAcyclicSignalConnector::Blocker(d->shapeChangedAcyclicConnector)); d->deactivationLocks.push_back(KisAcyclicSignalConnector::Blocker(d->resourceManagerAcyclicConnector)); } void KoFillConfigWidget::forceUpdateOnSelectionChanged() { shapeChanged(); } void KoFillConfigWidget::setNoSelectionTrackingMode(bool value) { d->noSelectionTrackingMode = value; if (!d->noSelectionTrackingMode) { shapeChanged(); } } void KoFillConfigWidget::slotUpdateFillTitle() { QString text = d->group->checkedButton() ? d->group->checkedButton()->text() : QString(); text.replace('&', QString()); d->ui->lblFillTitle->setText(text); } void KoFillConfigWidget::slotCanvasResourceChanged(int key, const QVariant &value) { if ((key == KoCanvasResourceProvider::ForegroundColor && d->fillVariant == KoFlake::Fill) || (key == KoCanvasResourceProvider::BackgroundColor && d->fillVariant == KoFlake::StrokeFill && !d->noSelectionTrackingMode) || (key == KoCanvasResourceProvider::ForegroundColor && d->noSelectionTrackingMode)) { KoColor color = value.value(); const int checkedId = d->group->checkedId(); if ((checkedId < 0 || checkedId == None || checkedId == Solid) && !(checkedId == Solid && d->colorAction->currentKoColor() == color)) { d->group->button(Solid)->setChecked(true); d->selectedFillIndex = Solid; d->colorAction->setCurrentColor(color); d->colorChangedCompressor.start(); } else if (checkedId == Gradient && key == KoCanvasResourceProvider::ForegroundColor) { d->ui->wdgGradientEditor->notifyGlobalColorChanged(color); } } else if (key == KisCanvasResourceProvider::CurrentGradient) { - KoResource *gradient = value.value(); + KoResourceSP gradient = value.value(); const int checkedId = d->group->checkedId(); if (gradient && (checkedId < 0 || checkedId == None || checkedId == Gradient)) { d->group->button(Gradient)->setChecked(true); d->gradientAction->setCurrentResource(gradient); } } } QList KoFillConfigWidget::currentShapes() { return d->canvas->selectedShapesProxy()->selection()->selectedEditableShapes(); } int KoFillConfigWidget::selectedFillIndex() { return d->selectedFillIndex; } void KoFillConfigWidget::styleButtonPressed(int buttonId) { switch (buttonId) { case KoFillConfigWidget::None: noColorSelected(); break; case KoFillConfigWidget::Solid: colorChanged(); break; case KoFillConfigWidget::Gradient: if (d->activeGradient) { activeGradientChanged(); } else { gradientResourceChanged(); } break; case KoFillConfigWidget::Pattern: // Only select mode in the widget, don't set actual pattern :/ //d->colorButton->setDefaultAction(d->patternAction); //patternChanged(d->patternAction->currentBackground()); break; } if (buttonId >= None && buttonId <= Pattern) { d->selectedFillIndex = static_cast(buttonId); updateWidgetComponentVisbility(); } } KoShapeStrokeSP KoFillConfigWidget::createShapeStroke() { KoShapeStrokeSP stroke(new KoShapeStroke()); KIS_ASSERT_RECOVER_RETURN_VALUE(d->fillVariant == KoFlake::StrokeFill, stroke); switch (d->group->checkedId()) { case KoFillConfigWidget::None: stroke->setColor(Qt::transparent); break; case KoFillConfigWidget::Solid: stroke->setColor(d->colorAction->currentColor()); break; case KoFillConfigWidget::Gradient: { QScopedPointer g(d->activeGradient->toQGradient()); QBrush newBrush = *g; stroke->setLineBrush(newBrush); stroke->setColor(Qt::transparent); break; } case KoFillConfigWidget::Pattern: break; } return stroke; } void KoFillConfigWidget::noColorSelected() { KisAcyclicSignalConnector::Blocker b(d->shapeChangedAcyclicConnector); QList selectedShapes = currentShapes(); if (selectedShapes.isEmpty()) { emit sigFillChanged(); return; } KoShapeFillWrapper wrapper(selectedShapes, d->fillVariant); KUndo2Command *command = wrapper.setColor(QColor()); if (command) { d->canvas->addCommand(command); } emit sigFillChanged(); } void KoFillConfigWidget::colorChanged() { KisAcyclicSignalConnector::Blocker b(d->shapeChangedAcyclicConnector); QList selectedShapes = currentShapes(); if (selectedShapes.isEmpty()) { emit sigInternalRequestColorToResourceManager(); emit sigFillChanged(); return; } KoShapeFillWrapper wrapper(selectedShapes, d->fillVariant); KUndo2Command *command = wrapper.setColor(d->colorAction->currentColor()); if (command) { d->canvas->addCommand(command); } emit sigInternalRequestColorToResourceManager(); emit sigFillChanged(); } void KoFillConfigWidget::slotProposeCurrentColorToResourceManager() { const int checkedId = d->group->checkedId(); bool hasColor = false; KoColor color; KoCanvasResourceProvider::CanvasResource colorSlot = KoCanvasResourceProvider::ForegroundColor; if (checkedId == Solid) { if (d->fillVariant == KoFlake::StrokeFill) { colorSlot = KoCanvasResourceProvider::BackgroundColor; } color = d->colorAction->currentKoColor(); hasColor = true; } else if (checkedId == Gradient) { if (boost::optional gradientColor = d->ui->wdgGradientEditor->currentActiveStopColor()) { color = *gradientColor; hasColor = true; } } if (hasColor) { /** * Don't let opacity leak to our resource manager system * * NOTE: theoretically, we could guarantee it on a level of the * resource manager itself, */ color.setOpacity(OPACITY_OPAQUE_U8); d->canvas->resourceManager()->setResource(colorSlot, QVariant::fromValue(color)); } } template QString findFirstAvailableResourceName(const QString &baseName, ResourceServer *server) { if (!server->resourceByName(baseName)) return baseName; int counter = 1; QString result; while ((result = QString("%1%2").arg(baseName).arg(counter)), server->resourceByName(result)) { counter++; } return result; } void KoFillConfigWidget::slotSavePredefinedGradientClicked() { KoResourceServerProvider *serverProvider = KoResourceServerProvider::instance(); auto server = serverProvider->gradientServer(); const QString defaultGradientNamePrefix = i18nc("default prefix for the saved gradient", "gradient"); QString name = d->activeGradient->name().isEmpty() ? defaultGradientNamePrefix : d->activeGradient->name(); name = findFirstAvailableResourceName(name, server); name = QInputDialog::getText(this, i18nc("@title:window", "Save Gradient"), i18n("Enter gradient name:"), QLineEdit::Normal, name); // TODO: currently we do not allow the user to // create two resources with the same name! // Please add some feedback for it! name = findFirstAvailableResourceName(name, server); d->activeGradient->setName(name); const QString saveLocation = server->saveLocation(); d->activeGradient->setFilename(saveLocation + d->activeGradient->name() + d->activeGradient->defaultFileExtension()); - KoAbstractGradient *newGradient = d->activeGradient->clone(); + KoAbstractGradientSP newGradient = d->activeGradient->clone(); server->addResource(newGradient); d->gradientAction->setCurrentResource(newGradient); } void KoFillConfigWidget::activeGradientChanged() { setNewGradientBackgroundToShape(); updateGradientSaveButtonAvailability(); emit sigInternalRequestColorToResourceManager(); } void KoFillConfigWidget::gradientResourceChanged() { QSharedPointer bg = qSharedPointerDynamicCast( d->gradientAction->currentBackground()); uploadNewGradientBackground(bg->gradient()); setNewGradientBackgroundToShape(); updateGradientSaveButtonAvailability(); } void KoFillConfigWidget::slotGradientTypeChanged() { QGradient::Type type = d->ui->cmbGradientType->currentIndex() == 0 ? QGradient::LinearGradient : QGradient::RadialGradient; d->activeGradient->setType(type); activeGradientChanged(); } void KoFillConfigWidget::slotGradientRepeatChanged() { QGradient::Spread spread = QGradient::Spread(d->ui->cmbGradientRepeat->currentIndex()); d->activeGradient->setSpread(spread); activeGradientChanged(); } void KoFillConfigWidget::uploadNewGradientBackground(const QGradient *gradient) { KisSignalsBlocker b1(d->ui->wdgGradientEditor, d->ui->cmbGradientType, d->ui->cmbGradientRepeat); d->ui->wdgGradientEditor->setGradient(0); - d->activeGradient.reset(KoStopGradient::fromQGradient(gradient)); + d->activeGradient = KoStopGradient::fromQGradient(gradient); - d->ui->wdgGradientEditor->setGradient(d->activeGradient.data()); + d->ui->wdgGradientEditor->setGradient(d->activeGradient); d->ui->cmbGradientType->setCurrentIndex(d->activeGradient->type() != QGradient::LinearGradient); d->ui->cmbGradientRepeat->setCurrentIndex(int(d->activeGradient->spread())); } void KoFillConfigWidget::setNewGradientBackgroundToShape() { QList selectedShapes = currentShapes(); if (selectedShapes.isEmpty()) { emit sigFillChanged(); return; } KisAcyclicSignalConnector::Blocker b(d->shapeChangedAcyclicConnector); KoShapeFillWrapper wrapper(selectedShapes, d->fillVariant); QScopedPointer srcQGradient(d->activeGradient->toQGradient()); KUndo2Command *command = wrapper.applyGradientStopsOnly(srcQGradient.data()); if (command) { d->canvas->addCommand(command); } emit sigFillChanged(); } void KoFillConfigWidget::updateGradientSaveButtonAvailability() { bool savingEnabled = false; QScopedPointer currentGradient(d->activeGradient->toQGradient()); QSharedPointer bg = d->gradientAction->currentBackground(); if (bg) { QSharedPointer resourceBackground = qSharedPointerDynamicCast(bg); savingEnabled = resourceBackground->gradient()->stops() != currentGradient->stops(); savingEnabled |= resourceBackground->gradient()->type() != currentGradient->type(); savingEnabled |= resourceBackground->gradient()->spread() != currentGradient->spread(); } d->ui->btnSaveGradient->setEnabled(savingEnabled); } void KoFillConfigWidget::patternChanged(QSharedPointer background) { Q_UNUSED(background); #if 0 QSharedPointer patternBackground = qSharedPointerDynamicCast(background); if (! patternBackground) { return; } QList selectedShapes = currentShapes(); if (selectedShapes.isEmpty()) { return; } KoImageCollection *imageCollection = d->canvas->shapeController()->resourceManager()->imageCollection(); if (imageCollection) { QSharedPointer fill(new KoPatternBackground(imageCollection)); fill->setPattern(patternBackground->pattern()); d->canvas->addCommand(new KoShapeBackgroundCommand(selectedShapes, fill)); } #endif } void KoFillConfigWidget::loadCurrentFillFromResourceServer() { { KoColor color = d->canvas->resourceManager()->backgroundColor(); slotCanvasResourceChanged(KoCanvasResourceProvider::BackgroundColor, QVariant::fromValue(color)); } { KoColor color = d->canvas->resourceManager()->foregroundColor(); slotCanvasResourceChanged(KoCanvasResourceProvider::ForegroundColor, QVariant::fromValue(color)); } Q_FOREACH (QAbstractButton *button, d->group->buttons()) { button->setEnabled(true); } emit sigFillChanged(); } void KoFillConfigWidget::shapeChanged() { if (d->noSelectionTrackingMode) return; QList shapes = currentShapes(); if (shapes.isEmpty() || (shapes.size() > 1 && KoShapeFillWrapper(shapes, d->fillVariant).isMixedFill())) { Q_FOREACH (QAbstractButton *button, d->group->buttons()) { button->setEnabled(!shapes.isEmpty()); } d->group->button(None)->setChecked(true); d->selectedFillIndex = None; } else { Q_FOREACH (QAbstractButton *button, d->group->buttons()) { button->setEnabled(true); } KoShape *shape = shapes.first(); updateWidget(shape); } } bool KoFillConfigWidget::checkNewFillModeIsSame(const KoShapeFillWrapper &w) const { bool retval = false; switch (w.type()) { case KoFlake::None: retval = d->selectedFillIndex == None; break; case KoFlake::Solid: retval = d->selectedFillIndex == Solid && w.color() == d->colorAction->currentColor(); break; case KoFlake::Gradient: { - QScopedPointer newGradient(KoStopGradient::fromQGradient(w.gradient())); + KoStopGradientSP newGradient(KoStopGradient::fromQGradient(w.gradient())); retval = d->selectedFillIndex == Gradient && *newGradient == *d->activeGradient; break; } case KoFlake::Pattern: // TODO: not implemented retval = d->selectedFillIndex == Pattern && false; break; } return retval; } void KoFillConfigWidget::updateWidget(KoShape *shape) { KIS_SAFE_ASSERT_RECOVER_RETURN(shape); StyleButton newActiveButton = None; KoShapeFillWrapper wrapper(shape, d->fillVariant); if (checkNewFillModeIsSame(wrapper)) return; switch (wrapper.type()) { case KoFlake::None: break; case KoFlake::Solid: { QColor color = wrapper.color(); if (color.alpha() > 0) { newActiveButton = KoFillConfigWidget::Solid; d->colorAction->setCurrentColor(wrapper.color()); } break; } case KoFlake::Gradient: newActiveButton = KoFillConfigWidget::Gradient; uploadNewGradientBackground(wrapper.gradient()); updateGradientSaveButtonAvailability(); break; case KoFlake::Pattern: newActiveButton = KoFillConfigWidget::Pattern; break; } d->group->button(newActiveButton)->setChecked(true); d->selectedFillIndex = newActiveButton; updateWidgetComponentVisbility(); } void KoFillConfigWidget::updateWidgetComponentVisbility() { // The UI is showing/hiding things like this because the 'stacked widget' isn't very flexible // and makes it difficult to put anything underneath it without a lot empty space // hide everything first d->ui->wdgGradientEditor->setVisible(false); d->ui->btnChoosePredefinedGradient->setVisible(false); d->ui->btnChooseSolidColor->setVisible(false); d->ui->typeLabel->setVisible(false); d->ui->repeatLabel->setVisible(false); d->ui->cmbGradientRepeat->setVisible(false); d->ui->cmbGradientType->setVisible(false); d->ui->btnSolidColorPick->setVisible(false); d->ui->btnSaveGradient->setVisible(false); d->ui->gradientTypeLine->setVisible(false); d->ui->soldStrokeColorLabel->setVisible(false); d->ui->presetLabel->setVisible(false); switch (d->selectedFillIndex) { case KoFillConfigWidget::None: break; case KoFillConfigWidget::Solid: d->ui->btnChooseSolidColor->setVisible(true); d->ui->btnSolidColorPick->setVisible(true); d->ui->soldStrokeColorLabel->setVisible(true); break; case KoFillConfigWidget::Gradient: d->ui->wdgGradientEditor->setVisible(true); d->ui->btnChoosePredefinedGradient->setVisible(true); d->ui->typeLabel->setVisible(true); d->ui->repeatLabel->setVisible(true); d->ui->cmbGradientRepeat->setVisible(true); d->ui->cmbGradientType->setVisible(true); d->ui->btnSaveGradient->setVisible(true); d->ui->gradientTypeLine->setVisible(true); d->ui->presetLabel->setVisible(true); break; case KoFillConfigWidget::Pattern: break; } } diff --git a/libs/ui/widgets/kis_cmb_gradient.cpp b/libs/ui/widgets/kis_cmb_gradient.cpp index 94328de49f..5771502306 100644 --- a/libs/ui/widgets/kis_cmb_gradient.cpp +++ b/libs/ui/widgets/kis_cmb_gradient.cpp @@ -1,78 +1,78 @@ /* * Copyright (c) 2015 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_cmb_gradient.h" #include #include #include #include #include #include #include #include "kis_gradient_chooser.h" KisCmbGradient::KisCmbGradient(QWidget *parent) : KisPopupButton(parent) , m_gradientChooser(new KisGradientChooser(this)) { - connect(m_gradientChooser, SIGNAL(resourceSelected(KoResource*)), SLOT(gradientSelected(KoResource*))); + connect(m_gradientChooser, SIGNAL(resourceSelected(KoResourceSP )), SLOT(gradientSelected(KoResourceSP ))); setPopupWidget(m_gradientChooser); } -void KisCmbGradient::setGradient(KoAbstractGradient *gradient) +void KisCmbGradient::setGradient(KoAbstractGradientSP gradient) { m_gradientChooser->setCurrentResource(gradient); } -KoAbstractGradient *KisCmbGradient::gradient() const +KoAbstractGradientSP KisCmbGradient::gradient() const { - return dynamic_cast(m_gradientChooser->currentResource()); + return m_gradientChooser->currentResource().dynamicCast(); } -void KisCmbGradient::gradientSelected(KoResource *resource) +void KisCmbGradient::gradientSelected(KoResourceSP resource) { - KoAbstractGradient *gradient = dynamic_cast(resource); + KoAbstractGradientSP gradient = resource.dynamicCast(); if (!gradient) return; QImage pm = gradient->generatePreview(iconSize().width(), iconSize().height()); setIcon(QIcon(QPixmap::fromImage(pm))); emit gradientChanged(gradient); } QSize KisCmbGradient::sizeHint() const { ensurePolished(); QFontMetrics fm = fontMetrics(); int maxW = 7 * fm.width(QChar('x')) + 18; int maxH = qMax(fm.lineSpacing(), 14) + 2; QStyleOptionComboBox options; options.initFrom(this); return style()->sizeFromContents(QStyle::CT_ComboBox, &options, QSize(maxW, maxH), this).expandedTo(QApplication::globalStrut()); } void KisCmbGradient::resizeEvent(QResizeEvent *event) { setIconSize(QSize(event->size().width() - 30, event->size().height() - 4)); KisPopupButton::resizeEvent(event); } diff --git a/libs/ui/widgets/kis_cmb_gradient.h b/libs/ui/widgets/kis_cmb_gradient.h index 8bf5bf618a..573f1ee95c 100644 --- a/libs/ui/widgets/kis_cmb_gradient.h +++ b/libs/ui/widgets/kis_cmb_gradient.h @@ -1,56 +1,57 @@ /* * Copyright (c) 2015 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. */ #ifndef KIS_CMB_GRADIENT_H #define KIS_CMB_GRADIENT_H #include +#include + class KoResource; class KisGradientChooser; -class KoAbstractGradient; /** * @brief The KisCmbGradient class allows the user to select a gradient. */ class KisCmbGradient : public KisPopupButton { Q_OBJECT public: explicit KisCmbGradient(QWidget *parent = 0); - void setGradient(KoAbstractGradient *gradient); - KoAbstractGradient *gradient() const; + void setGradient(KoAbstractGradientSP gradient); + KoAbstractGradientSP gradient() const; QSize sizeHint() const override; protected: void resizeEvent(QResizeEvent *event) override; Q_SIGNALS: - void gradientChanged(KoAbstractGradient*); + void gradientChanged(KoAbstractGradientSP); private Q_SLOTS: - void gradientSelected(KoResource *resource); + void gradientSelected(KoResourceSP resource); private: KisGradientChooser *m_gradientChooser; }; #endif // KIS_CMB_GRADIENT_H diff --git a/libs/ui/widgets/kis_gradient_chooser.cc b/libs/ui/widgets/kis_gradient_chooser.cc index 19c7ab6e67..92f77e4477 100644 --- a/libs/ui/widgets/kis_gradient_chooser.cc +++ b/libs/ui/widgets/kis_gradient_chooser.cc @@ -1,205 +1,205 @@ /* * Copyright (c) 2004 Adrian Page * Copyright (C) 2011 Srikanth Tiyyagura * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "widgets/kis_gradient_chooser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisViewManager.h" #include "kis_global.h" #include "kis_autogradient.h" #include "kis_canvas_resource_provider.h" #include "kis_stopgradient_editor.h" -KisCustomGradientDialog::KisCustomGradientDialog(KoAbstractGradient* gradient, QWidget * parent, const char *name) +KisCustomGradientDialog::KisCustomGradientDialog(KoAbstractGradientSP gradient, QWidget * parent, const char *name) : KoDialog(parent) { setCaption(i18n("Custom Gradient")); setButtons(Close); setDefaultButton(Close); setObjectName(name); setModal(false); - KoStopGradient* stopGradient = dynamic_cast(gradient); + KoStopGradientSP stopGradient = gradient.dynamicCast(); if (stopGradient) { m_page = new KisStopGradientEditor(stopGradient, this, "autogradient", i18n("Custom Gradient")); } - KoSegmentGradient* segmentedGradient = dynamic_cast(gradient); + KoSegmentGradientSP segmentedGradient = gradient.dynamicCast(); if (segmentedGradient) { m_page = new KisAutogradient(segmentedGradient, this, "autogradient", i18n("Custom Gradient")); } setMainWidget(m_page); } KisGradientChooser::KisGradientChooser(QWidget *parent, const char *name) : QFrame(parent) { setObjectName(name); m_lbName = new QLabel(); KoResourceServer * rserver = KoResourceServerProvider::instance()->gradientServer(); QSharedPointer adapter (new KoResourceServerAdapter(rserver)); m_itemChooser = new KoResourceItemChooser(adapter, this); m_itemChooser->showTaggingBar(true); m_itemChooser->setFixedSize(250, 250); m_itemChooser->setColumnCount(1); - connect(m_itemChooser, SIGNAL(resourceSelected(KoResource*)), - this, SLOT(update(KoResource*))); + connect(m_itemChooser, SIGNAL(resourceSelected(KoResourceSP )), + this, SLOT(update(KoResourceSP ))); - connect(m_itemChooser, SIGNAL(resourceSelected(KoResource*)), - this, SIGNAL(resourceSelected(KoResource*))); + 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() { } -KoResource *KisGradientChooser::currentResource() +KoResourceSP KisGradientChooser::currentResource() { return m_itemChooser->currentResource(); } -void KisGradientChooser::setCurrentResource(KoResource *resource) +void KisGradientChooser::setCurrentResource(KoResourceSP resource) { m_itemChooser->setCurrentResource(resource); } void KisGradientChooser::setCurrentItem(int row, int column) { m_itemChooser->setCurrentItem(row, column); if (currentResource()) update(currentResource()); } void KisGradientChooser::slotUpdateIcons() { if (m_addGradient && m_editGradient) { m_addGradient->setIcon(KisIconUtils::loadIcon("list-add")); m_editGradient->setIcon(KisIconUtils::loadIcon("configure")); } } -void KisGradientChooser::update(KoResource * resource) +void KisGradientChooser::update(KoResourceSP resource) { - KoAbstractGradient *gradient = static_cast(resource); + KoAbstractGradientSP gradient = resource.staticCast(); m_lbName->setText(gradient ? i18n(gradient->name().toUtf8().data()) : ""); m_editGradient->setEnabled(gradient && gradient->removable()); } void KisGradientChooser::addStopGradient() { - KoStopGradient* gradient = new KoStopGradient(""); + KoStopGradientSP gradient(new KoStopGradient("")); QList stops; stops << KoGradientStop(0.0, KoColor(QColor(250, 250, 0), KoColorSpaceRegistry::instance()->rgb8())) << KoGradientStop(1.0, KoColor(QColor(255, 0, 0, 255), KoColorSpaceRegistry::instance()->rgb8())); gradient->setType(QGradient::LinearGradient); gradient->setStops(stops); addGradient(gradient); } void KisGradientChooser::addSegmentedGradient() { - KoSegmentGradient* gradient = new KoSegmentGradient(""); + 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(KoAbstractGradient* gradient) +void KisGradientChooser::addGradient(KoAbstractGradientSP gradient) { KoResourceServer * rserver = KoResourceServerProvider::instance()->gradientServer(); QString saveLocation = rserver->saveLocation(); KisCustomGradientDialog dialog(gradient, this, "autogradient"); dialog.exec(); gradient->setFilename(saveLocation + gradient->name() + gradient->defaultFileExtension()); gradient->setValid(true); rserver->addResource(gradient); m_itemChooser->setCurrentResource(gradient); } void KisGradientChooser::editGradient() { - KisCustomGradientDialog dialog(static_cast(currentResource()), this, "autogradient"); + KisCustomGradientDialog dialog(currentResource().staticCast(), this, "autogradient"); dialog.exec(); } diff --git a/libs/ui/widgets/kis_gradient_chooser.h b/libs/ui/widgets/kis_gradient_chooser.h index d86da361b9..b55378e761 100644 --- a/libs/ui/widgets/kis_gradient_chooser.h +++ b/libs/ui/widgets/kis_gradient_chooser.h @@ -1,91 +1,93 @@ /* * Copyright (c) 2004 Adrian Page * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_GRADIENT_CHOOSER_H_ #define KIS_GRADIENT_CHOOSER_H_ #include #include #include #include +#include +#include +#include +#include -class KoAbstractGradient; -class KoStopGradient; class KisViewManager; class QLabel; class QPushButton; class KisAutogradient; -class KoResource; + class KoResourceItemChooser; class KisCustomGradientDialog : public KoDialog { Q_OBJECT public: - KisCustomGradientDialog(KoAbstractGradient* gradient, QWidget * parent, const char *name); + KisCustomGradientDialog(KoAbstractGradientSP gradient, QWidget * parent, const char *name); private: QWidget * m_page; }; class KRITAUI_EXPORT KisGradientChooser : public QFrame { Q_OBJECT public: KisGradientChooser(QWidget *parent = 0, const char *name = 0); ~KisGradientChooser() override; /// Gets the currently selected resource /// @returns the selected resource, 0 is no resource is selected - KoResource *currentResource(); - void setCurrentResource(KoResource *resource); + KoResourceSP currentResource(); + void setCurrentResource(KoResourceSP resource); void setCurrentItem(int row, int column); Q_SIGNALS: /// Emitted when a resource was selected - void resourceSelected(KoResource * resource); + void resourceSelected(KoResourceSP resource); public Q_SLOTS: void slotUpdateIcons(); private Q_SLOTS: - virtual void update(KoResource * resource); + virtual void update(KoResourceSP resource); void addStopGradient(); void addSegmentedGradient(); void editGradient(); private: - void addGradient(KoAbstractGradient* gradient); + void addGradient(KoAbstractGradientSP gradient); private: QLabel *m_lbName; KoResourceItemChooser * m_itemChooser; QToolButton* m_addGradient; QPushButton* m_editGradient; }; #endif // KIS_GRADIENT_CHOOSER_H_ diff --git a/libs/ui/widgets/kis_iconwidget.cc b/libs/ui/widgets/kis_iconwidget.cc index 4c498d41b5..06b8447ea0 100644 --- a/libs/ui/widgets/kis_iconwidget.cc +++ b/libs/ui/widgets/kis_iconwidget.cc @@ -1,112 +1,112 @@ /* * Copyright (c) 2000 Matthias Elter * Copyright (c) 2003 Patrick Julien * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details.g * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "widgets/kis_iconwidget.h" #include #include #include #include #include KisIconWidget::KisIconWidget(QWidget *parent, const char *name) : KisPopupButton(parent) { setObjectName(name); m_resource = 0; } -void KisIconWidget::slotSetItem(KoResource * resource) +void KisIconWidget::slotSetItem(KoResourceSP resource) { m_resource = resource; update(); } void KisIconWidget::paintEvent(QPaintEvent *event) { QPushButton::paintEvent(event); QPainter p; p.begin(this); const qint32 cw = width(); const qint32 ch = height(); const qint32 border = 3; const qint32 iconWidth = cw - (border*2); const qint32 iconHeight = ch - (border*2); // Round off the corners of the preview QRegion clipRegion(border, border, iconWidth, iconHeight); clipRegion -= QRegion(border, border, 1, 1); clipRegion -= QRegion(cw-border-1, border, 1, 1); clipRegion -= QRegion(cw-border-1, ch-border-1, 1, 1); clipRegion -= QRegion(border, ch-border-1, 1, 1); p.setClipRegion(clipRegion); p.setClipping(true); p.setBrush(this->palette().background()); p.drawRect(QRect(0,0,cw,ch)); if (m_resource) { QImage img = QImage(iconWidth, iconHeight, QImage::Format_ARGB32); img.fill(Qt::transparent); if (m_resource->image().width()image().height()image().width()) { for (int y=0; y< iconHeight; y+=m_resource->image().height()) { paint2.drawImage(x, y, m_resource->image()); } } } else { img = m_resource->image().scaled(iconWidth, iconHeight, Qt::KeepAspectRatio, Qt::SmoothTransformation); } p.drawImage(QRect(border, border, iconWidth, iconHeight), img); } else if (!icon().isNull()) { int border2 = qRound((cw-16)*0.5); p.drawImage(QRect(border2, border2, 16, 16), icon().pixmap(16, 16).toImage()); } p.setClipping(false); } void KisIconWidget::setResourceAdapter(QSharedPointer adapter) { Q_ASSERT(adapter); m_adapter = adapter; m_adapter->connectToResourceServer(); - connect(m_adapter.data(), SIGNAL(resourceChanged(KoResource*)), this, SLOT(slotAdapterResourceChanged(KoResource*))); - connect(m_adapter.data(), SIGNAL(removingResource(KoResource*)), this, SLOT(slotAdapterResourceRemoved(KoResource*))); + connect(m_adapter.data(), SIGNAL(resourceChanged(KoResourceSP )), this, SLOT(slotAdapterResourceChanged(KoResourceSP ))); + connect(m_adapter.data(), SIGNAL(removingResource(KoResourceSP )), this, SLOT(slotAdapterResourceRemoved(KoResourceSP ))); } -void KisIconWidget::slotAdapterResourceChanged(KoResource* resource) +void KisIconWidget::slotAdapterResourceChanged(KoResourceSP resource) { if (m_resource == resource) { update(); } } -void KisIconWidget::slotAdapterResourceRemoved(KoResource* resource) +void KisIconWidget::slotAdapterResourceRemoved(KoResourceSP resource) { if (m_resource == resource) { m_resource = 0; } } diff --git a/libs/ui/widgets/kis_iconwidget.h b/libs/ui/widgets/kis_iconwidget.h index b1b4f54246..6138ee5c80 100644 --- a/libs/ui/widgets/kis_iconwidget.h +++ b/libs/ui/widgets/kis_iconwidget.h @@ -1,58 +1,59 @@ /* * Copyright (c) 2000 Matthias Elter * Copyright (c) 2003 Patrick Julien * * 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_ICONWIDGET_H_ #define KIS_ICONWIDGET_H_ #include -class KoResource; +#include + class KoAbstractResourceServerAdapter; /** * The icon widget is used in the control box where the current color and brush * are shown. */ class KisIconWidget : public KisPopupButton { Q_OBJECT public: KisIconWidget(QWidget *parent = 0, const char *name = 0); /** * Set an resource server adapter that the widget will observe. */ void setResourceAdapter(QSharedPointer adapter); public Q_SLOTS: - void slotSetItem(KoResource * resource); - void slotAdapterResourceChanged(KoResource * resource); - void slotAdapterResourceRemoved(KoResource * resource); + void slotSetItem(KoResourceSP resource); + void slotAdapterResourceChanged(KoResourceSP resource); + void slotAdapterResourceRemoved(KoResourceSP resource); protected: void paintEvent(QPaintEvent *) override; private: - KoResource *m_resource; + KoResourceSP m_resource; QSharedPointer m_adapter; }; #endif // KIS_ICONWIDGET_H_ diff --git a/libs/ui/widgets/kis_paintop_presets_chooser_popup.cpp b/libs/ui/widgets/kis_paintop_presets_chooser_popup.cpp index fed72e79fc..229398c139 100644 --- a/libs/ui/widgets/kis_paintop_presets_chooser_popup.cpp +++ b/libs/ui/widgets/kis_paintop_presets_chooser_popup.cpp @@ -1,165 +1,165 @@ /* This file is part of the KDE project * Copyright (c) 2010 Sven Langkamp * Copyright 2011 Srikanth Tiyyagura * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_paintop_presets_chooser_popup.h" #include #include #include #include #include #include #include #include #include #include #include #include #include struct KisPaintOpPresetsChooserPopup::Private { public: Ui_WdgPaintOpPresets uiWdgPaintOpPresets; bool firstShown; QToolButton *viewModeButton; }; KisPaintOpPresetsChooserPopup::KisPaintOpPresetsChooserPopup(QWidget * parent) : QWidget(parent) , m_d(new Private()) { m_d->uiWdgPaintOpPresets.setupUi(this); QMenu* menu = new QMenu(this); menu->setStyleSheet("margin: 6px"); menu->addSection(i18n("Display")); QActionGroup *actionGroup = new QActionGroup(this); KisPresetChooser::ViewMode mode = (KisPresetChooser::ViewMode)KisConfig(true).presetChooserViewMode(); QAction* action = menu->addAction(KisIconUtils::loadIcon("view-preview"), i18n("Thumbnails"), this, SLOT(slotThumbnailMode())); action->setCheckable(true); action->setChecked(mode == KisPresetChooser::THUMBNAIL); action->setActionGroup(actionGroup); action = menu->addAction(KisIconUtils::loadIcon("view-list-details"), i18n("Details"), this, SLOT(slotDetailMode())); action->setCheckable(true); action->setChecked(mode == KisPresetChooser::DETAIL); action->setActionGroup(actionGroup); // add widget slider to control icon size QSlider* iconSizeSlider = new QSlider(this); iconSizeSlider->setOrientation(Qt::Horizontal); iconSizeSlider->setRange(30, 80); iconSizeSlider->setValue(m_d->uiWdgPaintOpPresets.wdgPresetChooser->iconSize()); iconSizeSlider->setMinimumHeight(20); iconSizeSlider->setMinimumWidth(40); iconSizeSlider->setTickInterval(10); QWidgetAction *sliderAction= new QWidgetAction(this); sliderAction->setDefaultWidget(iconSizeSlider); menu->addSection(i18n("Icon Size")); menu->addAction(sliderAction); // setting the view mode m_d->uiWdgPaintOpPresets.wdgPresetChooser->setViewMode(mode); m_d->uiWdgPaintOpPresets.wdgPresetChooser->showTaggingBar(true); m_d->uiWdgPaintOpPresets.wdgPresetChooser->itemChooser()->setViewModeButtonVisible(true); m_d->viewModeButton = m_d->uiWdgPaintOpPresets.wdgPresetChooser->itemChooser()->viewModeButton(); m_d->viewModeButton->setMenu(menu); m_d->viewModeButton->setIcon(KisIconUtils::loadIcon("configure")); - connect(m_d->uiWdgPaintOpPresets.wdgPresetChooser, SIGNAL(resourceSelected(KoResource*)), - this, SIGNAL(resourceSelected(KoResource*))); - connect(m_d->uiWdgPaintOpPresets.wdgPresetChooser, SIGNAL(resourceClicked(KoResource*)), - this, SIGNAL(resourceClicked(KoResource*))) ; + connect(m_d->uiWdgPaintOpPresets.wdgPresetChooser, SIGNAL(resourceSelected(KoResourceSP )), + this, SIGNAL(resourceSelected(KoResourceSP ))); + connect(m_d->uiWdgPaintOpPresets.wdgPresetChooser, SIGNAL(resourceClicked(KoResourceSP )), + this, SIGNAL(resourceClicked(KoResourceSP ))) ; connect (iconSizeSlider, SIGNAL(sliderMoved(int)), m_d->uiWdgPaintOpPresets.wdgPresetChooser, SLOT(setIconSize(int))); connect( iconSizeSlider, SIGNAL(sliderReleased()), m_d->uiWdgPaintOpPresets.wdgPresetChooser, SLOT(saveIconSize())); m_d->firstShown = true; } KisPaintOpPresetsChooserPopup::~KisPaintOpPresetsChooserPopup() { delete m_d; } void KisPaintOpPresetsChooserPopup::slotThumbnailMode() { KisConfig(false).setPresetChooserViewMode(KisPresetChooser::THUMBNAIL); m_d->uiWdgPaintOpPresets.wdgPresetChooser->setViewMode(KisPresetChooser::THUMBNAIL); } void KisPaintOpPresetsChooserPopup::slotDetailMode() { KisConfig(false).setPresetChooserViewMode(KisPresetChooser::DETAIL); m_d->uiWdgPaintOpPresets.wdgPresetChooser->setViewMode(KisPresetChooser::DETAIL); } void KisPaintOpPresetsChooserPopup::paintEvent(QPaintEvent* event) { QWidget::paintEvent(event); //Workaround to get the column and row size right if(m_d->firstShown) { m_d->uiWdgPaintOpPresets.wdgPresetChooser->updateViewSettings(); m_d->firstShown = false; } } void KisPaintOpPresetsChooserPopup::showButtons(bool show) { m_d->uiWdgPaintOpPresets.wdgPresetChooser->showButtons(show); } void KisPaintOpPresetsChooserPopup::canvasResourceChanged(KisPaintOpPresetSP preset) { if (preset) { blockSignals(true); - m_d->uiWdgPaintOpPresets.wdgPresetChooser->setCurrentResource(preset.data()); + m_d->uiWdgPaintOpPresets.wdgPresetChooser->setCurrentResource(preset); blockSignals(false); } m_d->uiWdgPaintOpPresets.wdgPresetChooser->updateViewSettings(); } void KisPaintOpPresetsChooserPopup::slotThemeChanged() { m_d->viewModeButton->setIcon(KisIconUtils::loadIcon("configure")); } void KisPaintOpPresetsChooserPopup::updateViewSettings() { m_d->uiWdgPaintOpPresets.wdgPresetChooser->updateViewSettings(); } diff --git a/libs/ui/widgets/kis_paintop_presets_chooser_popup.h b/libs/ui/widgets/kis_paintop_presets_chooser_popup.h index 98a4bf73a4..fc10e98ec8 100644 --- a/libs/ui/widgets/kis_paintop_presets_chooser_popup.h +++ b/libs/ui/widgets/kis_paintop_presets_chooser_popup.h @@ -1,59 +1,59 @@ /* This file is part of the KDE project * Copyright (c) 2010 Sven Langkamp * Copyright 2011 Srikanth Tiyyagura * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KIS_PAINTOP_PRESETS_CHOOSER_POPUP_H #define KIS_PAINTOP_PRESETS_CHOOSER_POPUP_H #include #include #include #include class KoResource; class KRITAUI_EXPORT KisPaintOpPresetsChooserPopup : public QWidget { Q_OBJECT public: KisPaintOpPresetsChooserPopup(QWidget * parent = 0); ~KisPaintOpPresetsChooserPopup() override; void showButtons(bool show); void updateViewSettings(); public Q_SLOTS: void canvasResourceChanged(KisPaintOpPresetSP preset ); void slotThemeChanged(); Q_SIGNALS: - void resourceSelected( KoResource * resource); - void resourceClicked( KoResource * resource); + void resourceSelected( KoResourceSP resource); + void resourceClicked( KoResourceSP resource); private Q_SLOTS: void slotThumbnailMode(); void slotDetailMode(); void paintEvent(QPaintEvent* ) override; private: struct Private; Private * const m_d; }; #endif // KIS_PAINTOP_PRESETS_CHOOSER_POPUP_H diff --git a/libs/ui/widgets/kis_paintop_presets_popup.cpp b/libs/ui/widgets/kis_paintop_presets_popup.cpp index ea87a4ba51..425cfabd5c 100644 --- a/libs/ui/widgets/kis_paintop_presets_popup.cpp +++ b/libs/ui/widgets/kis_paintop_presets_popup.cpp @@ -1,850 +1,850 @@ /* This file is part of the KDE project * Copyright (C) 2008 Boudewijn Rempt * Copyright (C) 2010 Lukáš Tvrdý * Copyright (C) 2011 Silvio Heinrich * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "widgets/kis_paintop_presets_popup.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_config.h" #include "KisResourceServerProvider.h" #include "kis_lod_availability_widget.h" #include "kis_signal_auto_connection.h" #include // ones from brush engine selector #include #include struct KisPaintOpPresetsPopup::Private { public: Ui_WdgPaintOpSettings uiWdgPaintOpPresetSettings; QGridLayout *layout; KisPaintOpConfigWidget *settingsWidget; QFont smallFont; KisCanvasResourceProvider *resourceProvider; KisFavoriteResourceManager *favoriteResManager; bool detached; bool ignoreHideEvents; bool isCreatingBrushFromScratch = false; QSize minimumSettingsWidgetSize; QRect detachedGeometry; KisSignalAutoConnectionsStore widgetConnections; }; KisPaintOpPresetsPopup::KisPaintOpPresetsPopup(KisCanvasResourceProvider * resourceProvider, KisFavoriteResourceManager* favoriteResourceManager, KisPresetSaveWidget* savePresetWidget, QWidget * parent) : QWidget(parent) , m_d(new Private()) { setObjectName("KisPaintOpPresetsPopup"); setFont(KoDockRegistry::dockFont()); current_paintOpId = ""; m_d->resourceProvider = resourceProvider; m_d->favoriteResManager = favoriteResourceManager; m_d->uiWdgPaintOpPresetSettings.setupUi(this); m_d->layout = new QGridLayout(m_d->uiWdgPaintOpPresetSettings.frmOptionWidgetContainer); m_d->layout->setSizeConstraint(QLayout::SetFixedSize); m_d->uiWdgPaintOpPresetSettings.scratchPad->setupScratchPad(resourceProvider, Qt::white); m_d->uiWdgPaintOpPresetSettings.scratchPad->setCutoutOverlayRect(QRect(25, 25, 200, 200)); m_d->uiWdgPaintOpPresetSettings.dirtyPresetIndicatorButton->setToolTip(i18n("The settings for this preset have changed from their default.")); m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setToolTip(i18n("Toggle showing presets")); m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setToolTip(i18n("Toggle showing scratchpad")); m_d->uiWdgPaintOpPresetSettings.reloadPresetButton->setToolTip(i18n("Reload the brush preset")); m_d->uiWdgPaintOpPresetSettings.renameBrushPresetButton->setToolTip(i18n("Rename the brush preset")); // creating a new preset from scratch. Part of the brush presets area // the menu options will get filled up later when we are generating all available paintops // in the filter drop-down newPresetBrushEnginesMenu = new QMenu(); // overwrite existing preset and saving a new preset use the same dialog saveDialog = savePresetWidget; saveDialog->scratchPadSetup(resourceProvider); saveDialog->setFavoriteResourceManager(m_d->favoriteResManager); // this is needed when saving the preset saveDialog->hide(); // the area on the brush editor for renaming the brush. make sure edit fields are hidden by default toggleBrushRenameUIActive(false); // DETAIL and THUMBNAIL view changer QMenu* menu = new QMenu(this); menu->setStyleSheet("margin: 6px"); menu->addSection(i18n("Display")); QActionGroup *actionGroup = new QActionGroup(this); KisPresetChooser::ViewMode mode = (KisPresetChooser::ViewMode)KisConfig(true).presetChooserViewMode(); QAction* action = menu->addAction(KisIconUtils::loadIcon("view-preview"), i18n("Thumbnails"), m_d->uiWdgPaintOpPresetSettings.presetWidget, SLOT(slotThumbnailMode())); action->setCheckable(true); action->setChecked(mode == KisPresetChooser::THUMBNAIL); action->setActionGroup(actionGroup); action = menu->addAction(KisIconUtils::loadIcon("view-list-details"), i18n("Details"), m_d->uiWdgPaintOpPresetSettings.presetWidget, SLOT(slotDetailMode())); action->setCheckable(true); action->setChecked(mode == KisPresetChooser::DETAIL); action->setActionGroup(actionGroup); // add horizontal slider for the icon size QSlider* iconSizeSlider = new QSlider(this); iconSizeSlider->setOrientation(Qt::Horizontal); iconSizeSlider->setRange(30, 80); iconSizeSlider->setValue(m_d->uiWdgPaintOpPresetSettings.presetWidget->iconSize()); iconSizeSlider->setMinimumHeight(20); iconSizeSlider->setMinimumWidth(40); iconSizeSlider->setTickInterval(10); QWidgetAction *sliderAction= new QWidgetAction(this); sliderAction->setDefaultWidget(iconSizeSlider); menu->addSection(i18n("Icon Size")); menu->addAction(sliderAction); // configure the button and assign menu m_d->uiWdgPaintOpPresetSettings.presetChangeViewToolButton->setMenu(menu); m_d->uiWdgPaintOpPresetSettings.presetChangeViewToolButton->setPopupMode(QToolButton::InstantPopup); // loading preset from scratch option m_d->uiWdgPaintOpPresetSettings.newPresetEngineButton->setPopupMode(QToolButton::InstantPopup); // show/hide buttons KisConfig cfg(true); m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setCheckable(true); m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setChecked(cfg.scratchpadVisible()); if (cfg.scratchpadVisible()) { slotSwitchScratchpad(true); // show scratchpad } else { slotSwitchScratchpad(false); } m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setCheckable(true); m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setChecked(false); slotSwitchShowPresets(false); // hide presets by default // Connections connect(m_d->uiWdgPaintOpPresetSettings.paintPresetIcon, SIGNAL(clicked()), m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(paintPresetImage())); - connect(saveDialog, SIGNAL(resourceSelected(KoResource*)), this, SLOT(resourceSelected(KoResource*))); + connect(saveDialog, SIGNAL(resourceSelected(KoResourceSP )), this, SLOT(resourceSelected(KoResourceSP ))); connect (m_d->uiWdgPaintOpPresetSettings.renameBrushPresetButton, SIGNAL(clicked(bool)), this, SLOT(slotRenameBrushActivated())); connect (m_d->uiWdgPaintOpPresetSettings.cancelBrushNameUpdateButton, SIGNAL(clicked(bool)), this, SLOT(slotRenameBrushDeactivated())); connect(m_d->uiWdgPaintOpPresetSettings.updateBrushNameButton, SIGNAL(clicked(bool)), this, SLOT(slotSaveRenameCurrentBrush())); connect(m_d->uiWdgPaintOpPresetSettings.renameBrushNameTextField, SIGNAL(returnPressed()), SLOT(slotSaveRenameCurrentBrush())); connect(iconSizeSlider, SIGNAL(sliderMoved(int)), m_d->uiWdgPaintOpPresetSettings.presetWidget, SLOT(slotSetIconSize(int))); connect(iconSizeSlider, SIGNAL(sliderReleased()), m_d->uiWdgPaintOpPresetSettings.presetWidget, SLOT(slotSaveIconSize())); connect(m_d->uiWdgPaintOpPresetSettings.showScratchpadButton, SIGNAL(clicked(bool)), this, SLOT(slotSwitchScratchpad(bool))); connect(m_d->uiWdgPaintOpPresetSettings.showPresetsButton, SIGNAL(clicked(bool)), this, SLOT(slotSwitchShowPresets(bool))); connect(m_d->uiWdgPaintOpPresetSettings.eraseScratchPad, SIGNAL(clicked()), m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(fillDefault())); connect(m_d->uiWdgPaintOpPresetSettings.fillLayer, SIGNAL(clicked()), m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(fillLayer())); connect(m_d->uiWdgPaintOpPresetSettings.fillGradient, SIGNAL(clicked()), m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(fillGradient())); connect(m_d->uiWdgPaintOpPresetSettings.fillSolid, SIGNAL(clicked()), m_d->uiWdgPaintOpPresetSettings.scratchPad, SLOT(fillBackground())); m_d->settingsWidget = 0; setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); connect(m_d->uiWdgPaintOpPresetSettings.saveBrushPresetButton, SIGNAL(clicked()), this, SLOT(slotSaveBrushPreset())); connect(m_d->uiWdgPaintOpPresetSettings.saveNewBrushPresetButton, SIGNAL(clicked()), this, SLOT(slotSaveNewBrushPreset())); connect(m_d->uiWdgPaintOpPresetSettings.reloadPresetButton, SIGNAL(clicked()), this, SIGNAL(reloadPresetClicked())); connect(m_d->uiWdgPaintOpPresetSettings.dirtyPresetCheckBox, SIGNAL(toggled(bool)), this, SIGNAL(dirtyPresetToggled(bool))); connect(m_d->uiWdgPaintOpPresetSettings.eraserBrushSizeCheckBox, SIGNAL(toggled(bool)), this, SIGNAL(eraserBrushSizeToggled(bool))); connect(m_d->uiWdgPaintOpPresetSettings.eraserBrushOpacityCheckBox, SIGNAL(toggled(bool)), this, SIGNAL(eraserBrushOpacityToggled(bool))); // preset widget connections - connect(m_d->uiWdgPaintOpPresetSettings.presetWidget->smallPresetChooser, SIGNAL(resourceSelected(KoResource*)), - this, SIGNAL(signalResourceSelected(KoResource*))); + connect(m_d->uiWdgPaintOpPresetSettings.presetWidget->smallPresetChooser, SIGNAL(resourceSelected(KoResourceSP )), + this, SIGNAL(signalResourceSelected(KoResourceSP ))); connect(m_d->uiWdgPaintOpPresetSettings.reloadPresetButton, SIGNAL(clicked()), m_d->uiWdgPaintOpPresetSettings.presetWidget->smallPresetChooser, SLOT(updateViewSettings())); connect(m_d->uiWdgPaintOpPresetSettings.reloadPresetButton, SIGNAL(clicked()), SLOT(slotUpdatePresetSettings())); m_d->detached = false; m_d->ignoreHideEvents = false; m_d->minimumSettingsWidgetSize = QSize(0, 0); m_d->detachedGeometry = QRect(100, 100, 0, 0); m_d->uiWdgPaintOpPresetSettings.dirtyPresetCheckBox->setChecked(cfg.useDirtyPresets()); m_d->uiWdgPaintOpPresetSettings.eraserBrushSizeCheckBox->setChecked(cfg.useEraserBrushSize()); m_d->uiWdgPaintOpPresetSettings.eraserBrushOpacityCheckBox->setChecked(cfg.useEraserBrushOpacity()); m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability->setCanvasResourceManager(resourceProvider->resourceManager()); connect(resourceProvider->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)), SLOT(slotResourceChanged(int,QVariant))); connect(m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability, SIGNAL(sigUserChangedLodAvailability(bool)), SLOT(slotLodAvailabilityChanged(bool))); connect(m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability, SIGNAL(sigUserChangedLodThreshold(qreal)), SLOT(slotLodThresholdChanged(qreal))); slotResourceChanged(KisCanvasResourceProvider::LodAvailability, resourceProvider->resourceManager()-> resource(KisCanvasResourceProvider::LodAvailability)); slotResourceChanged(KisCanvasResourceProvider::LodSizeThreshold, resourceProvider->resourceManager()-> resource(KisCanvasResourceProvider::LodSizeThreshold)); connect(m_d->uiWdgPaintOpPresetSettings.brushEgineComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotUpdatePaintOpFilter())); connect(m_d->uiWdgPaintOpPresetSettings.bnBlacklistPreset, SIGNAL(clicked()), this, SLOT(slotBlackListCurrentPreset())); updateThemedIcons(); // setup things like the scene construct images, layers, etc that is a one-time thing m_d->uiWdgPaintOpPresetSettings.liveBrushPreviewView->setup(); } void KisPaintOpPresetsPopup::slotBlackListCurrentPreset() { KisPaintOpPresetResourceServer * rServer = KisResourceServerProvider::instance()->paintOpPresetServer(); KisPaintOpPresetSP curPreset = m_d->resourceProvider->currentPreset(); if (rServer->resourceByName(curPreset->name())) { rServer->removeResourceAndBlacklist(curPreset); } } void KisPaintOpPresetsPopup::slotRenameBrushActivated() { toggleBrushRenameUIActive(true); } void KisPaintOpPresetsPopup::slotRenameBrushDeactivated() { toggleBrushRenameUIActive(false); } void KisPaintOpPresetsPopup::toggleBrushRenameUIActive(bool isRenaming) { // This function doesn't really do anything except get the UI in a state to rename a brush preset m_d->uiWdgPaintOpPresetSettings.renameBrushNameTextField->setVisible(isRenaming); m_d->uiWdgPaintOpPresetSettings.updateBrushNameButton->setVisible(isRenaming); m_d->uiWdgPaintOpPresetSettings.cancelBrushNameUpdateButton->setVisible(isRenaming); // hide these below areas while renaming m_d->uiWdgPaintOpPresetSettings.currentBrushNameLabel->setVisible(!isRenaming); m_d->uiWdgPaintOpPresetSettings.renameBrushPresetButton->setVisible(!isRenaming); m_d->uiWdgPaintOpPresetSettings.saveBrushPresetButton->setEnabled(!isRenaming); m_d->uiWdgPaintOpPresetSettings.saveBrushPresetButton->setVisible(!isRenaming); m_d->uiWdgPaintOpPresetSettings.saveNewBrushPresetButton->setEnabled(!isRenaming); m_d->uiWdgPaintOpPresetSettings.saveNewBrushPresetButton->setVisible(!isRenaming); // if the presets area is shown, only then can you show/hide the load default brush // need to think about weird state when you are in the middle of renaming a brush // what happens if you try to change presets. maybe we should auto-hide (or disable) // the presets area in this case if (m_d->uiWdgPaintOpPresetSettings.presetWidget->isVisible()) { m_d->uiWdgPaintOpPresetSettings.newPresetEngineButton->setVisible(!isRenaming); m_d->uiWdgPaintOpPresetSettings.bnBlacklistPreset->setVisible(!isRenaming); } } void KisPaintOpPresetsPopup::slotSaveRenameCurrentBrush() { // if you are renaming a brush, that is different than updating the settings // make sure we are in a clean state before renaming. This logic might change, // but that is what we are going with for now emit reloadPresetClicked(); m_d->favoriteResManager->setBlockUpdates(true); // get a reference to the existing (and new) file name and path that we are working with KisPaintOpPresetSP curPreset = m_d->resourceProvider->currentPreset(); if (!curPreset) return; KisPaintOpPresetResourceServer * rServer = KisResourceServerProvider::instance()->paintOpPresetServer(); QString saveLocation = rServer->saveLocation(); QString originalPresetName = curPreset->name(); QString renamedPresetName = m_d->uiWdgPaintOpPresetSettings.renameBrushNameTextField->text(); QString originalPresetPathAndFile = saveLocation + originalPresetName + curPreset->defaultFileExtension(); QString renamedPresetPathAndFile = saveLocation + renamedPresetName + curPreset->defaultFileExtension(); // create a new brush preset with the name specified and add to resource provider KisPaintOpPresetSP newPreset = curPreset->clone(); newPreset->setFilename(renamedPresetPathAndFile); // this also contains the path newPreset->setName(renamedPresetName); newPreset->setImage(curPreset->image()); // use existing thumbnail (might not need to do this) newPreset->setPresetDirty(false); newPreset->setValid(true); rServer->addResource(newPreset); - resourceSelected(newPreset.data()); // refresh and select our freshly renamed resource + resourceSelected(newPreset); // refresh and select our freshly renamed resource // Now blacklist the original file if (rServer->resourceByName(originalPresetName)) { rServer->removeResourceAndBlacklist(curPreset); } m_d->favoriteResManager->setBlockUpdates(false); toggleBrushRenameUIActive(false); // this returns the UI to its original state after saving slotUpdatePresetSettings(); // update visibility of dirty preset and icon } void KisPaintOpPresetsPopup::slotResourceChanged(int key, const QVariant &value) { if (key == KisCanvasResourceProvider::LodAvailability) { m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability->slotUserChangedLodAvailability(value.toBool()); } else if (key == KisCanvasResourceProvider::LodSizeThreshold) { m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability->slotUserChangedLodThreshold(value.toDouble()); } else if (key == KisCanvasResourceProvider::Size) { m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability->slotUserChangedSize(value.toDouble()); } } void KisPaintOpPresetsPopup::slotLodAvailabilityChanged(bool value) { m_d->resourceProvider->resourceManager()->setResource(KisCanvasResourceProvider::LodAvailability, QVariant(value)); } void KisPaintOpPresetsPopup::slotLodThresholdChanged(qreal value) { m_d->resourceProvider->resourceManager()->setResource(KisCanvasResourceProvider::LodSizeThreshold, QVariant(value)); } KisPaintOpPresetsPopup::~KisPaintOpPresetsPopup() { if (m_d->settingsWidget) { m_d->layout->removeWidget(m_d->settingsWidget); m_d->settingsWidget->hide(); m_d->settingsWidget->setParent(0); m_d->settingsWidget = 0; } delete m_d; delete newPresetBrushEnginesMenu; } void KisPaintOpPresetsPopup::setPaintOpSettingsWidget(QWidget * widget) { if (m_d->settingsWidget) { m_d->layout->removeWidget(m_d->settingsWidget); m_d->uiWdgPaintOpPresetSettings.frmOptionWidgetContainer->updateGeometry(); } m_d->layout->update(); updateGeometry(); m_d->widgetConnections.clear(); m_d->settingsWidget = 0; if (widget) { m_d->settingsWidget = dynamic_cast(widget); KIS_ASSERT_RECOVER_RETURN(m_d->settingsWidget); KisConfig cfg(true); if (m_d->settingsWidget->supportScratchBox() && cfg.scratchpadVisible()) { slotSwitchScratchpad(true); } else { slotSwitchScratchpad(false); } m_d->widgetConnections.addConnection(m_d->settingsWidget, SIGNAL(sigConfigurationItemChanged()), this, SLOT(slotUpdateLodAvailability())); widget->setFont(m_d->smallFont); QSize hint = widget->sizeHint(); m_d->minimumSettingsWidgetSize = QSize(qMax(hint.width(), m_d->minimumSettingsWidgetSize.width()), qMax(hint.height(), m_d->minimumSettingsWidgetSize.height())); widget->setMinimumSize(m_d->minimumSettingsWidgetSize); m_d->layout->addWidget(widget); // hook up connections that will monitor if our preset is dirty or not. Show a notification if it is if (m_d->resourceProvider && m_d->resourceProvider->currentPreset() ) { KisPaintOpPresetSP preset = m_d->resourceProvider->currentPreset(); m_d->widgetConnections.addConnection(preset->updateProxy(), SIGNAL(sigSettingsChanged()), this, SLOT(slotUpdatePresetSettings())); } m_d->layout->update(); widget->show(); } slotUpdateLodAvailability(); } void KisPaintOpPresetsPopup::slotUpdateLodAvailability() { if (!m_d->settingsWidget) return; KisPaintopLodLimitations l = m_d->settingsWidget->lodLimitations(); m_d->uiWdgPaintOpPresetSettings.wdgLodAvailability->setLimitations(l); } QImage KisPaintOpPresetsPopup::cutOutOverlay() { return m_d->uiWdgPaintOpPresetSettings.scratchPad->cutoutOverlay(); } void KisPaintOpPresetsPopup::contextMenuEvent(QContextMenuEvent *e) { Q_UNUSED(e); } void KisPaintOpPresetsPopup::switchDetached(bool show) { if (parentWidget()) { m_d->detached = !m_d->detached; if (m_d->detached) { m_d->ignoreHideEvents = true; if (show) { parentWidget()->show(); } m_d->ignoreHideEvents = false; } else { parentWidget()->hide(); } KisConfig cfg(false); cfg.setPaintopPopupDetached(m_d->detached); } } void KisPaintOpPresetsPopup::setCreatingBrushFromScratch(bool enabled) { m_d->isCreatingBrushFromScratch = enabled; } -void KisPaintOpPresetsPopup::resourceSelected(KoResource* resource) +void KisPaintOpPresetsPopup::resourceSelected(KoResourceSP resource) { // this gets called every time the brush editor window is opened // TODO: this gets called multiple times whenever the preset is changed in the presets area // the connections probably need to be thought about with this a bit more to keep things in sync m_d->uiWdgPaintOpPresetSettings.presetWidget->smallPresetChooser->setCurrentResource(resource); // find the display name of the brush engine and append it to the selected preset display QString currentBrushEngineName; QPixmap currentBrushEngineIcon = QPixmap(26, 26); currentBrushEngineIcon.fill(Qt::transparent); for(int i=0; i < sortedBrushEnginesList.length(); i++) { if (sortedBrushEnginesList.at(i).id == currentPaintOpId() ) { currentBrushEngineName = sortedBrushEnginesList.at(i).name; currentBrushEngineIcon = sortedBrushEnginesList.at(i).icon.pixmap(26, 26); } } // brush names have underscores as part of the file name (to help with building). We don't really need underscores // when viewing the names, so replace them with spaces QString formattedBrushName = resource->name().replace("_", " "); m_d->uiWdgPaintOpPresetSettings.currentBrushNameLabel->setText(formattedBrushName); m_d->uiWdgPaintOpPresetSettings.currentBrushEngineLabel->setText(i18nc("%1 is the name of a brush engine", "%1 Engine", currentBrushEngineName)); m_d->uiWdgPaintOpPresetSettings.currentBrushEngineIcon->setPixmap(currentBrushEngineIcon); m_d->uiWdgPaintOpPresetSettings.renameBrushNameTextField->setText(resource->name()); // use file name // get the preset image and pop it into the thumbnail area on the top of the brush editor m_d->uiWdgPaintOpPresetSettings.presetThumbnailicon->setPixmap(QPixmap::fromImage(resource->image().scaled(55, 55, Qt::KeepAspectRatio, Qt::SmoothTransformation))); toggleBrushRenameUIActive(false); // reset the UI state of renaming a brush if we are changing brush presets slotUpdatePresetSettings(); // check to see if the dirty preset icon needs to be shown } bool variantLessThan(const KisPaintOpInfo v1, const KisPaintOpInfo v2) { return v1.priority < v2.priority; } void KisPaintOpPresetsPopup::setPaintOpList(const QList< KisPaintOpFactory* >& list) { m_d->uiWdgPaintOpPresetSettings.brushEgineComboBox->clear(); // reset combobox list just in case // create a new list so we can sort it and populate the brush engine combo box sortedBrushEnginesList.clear(); // just in case this function is called again, don't keep adding to the list for(int i=0; i < list.length(); i++) { KisPaintOpInfo paintOpInfo; paintOpInfo.id = list.at(i)->id(); paintOpInfo.name = list.at(i)->name(); paintOpInfo.icon = list.at(i)->icon(); paintOpInfo.priority = list.at(i)->priority(); sortedBrushEnginesList.append(paintOpInfo); } std::stable_sort(sortedBrushEnginesList.begin(), sortedBrushEnginesList.end(), variantLessThan ); // add an "All" option at the front to show all presets QPixmap emptyPixmap = QPixmap(22,22); emptyPixmap.fill(Qt::transparent); // if we create a new brush from scratch, we need a full list of paintops to choose from // we don't want "All", so populate the list before that is added newPresetBrushEnginesMenu->actions().clear(); // clean out list in case we run this again newBrushEngineOptions.clear(); for (int j = 0; j < sortedBrushEnginesList.length(); j++) { KisAction * newEngineAction = static_cast( newPresetBrushEnginesMenu->addAction(sortedBrushEnginesList[j].name)); newEngineAction->setObjectName(sortedBrushEnginesList[j].id); // we need the ID for changing the paintop when action triggered newEngineAction->setIcon(sortedBrushEnginesList[j].icon); newBrushEngineOptions.append(newEngineAction); connect(newEngineAction, SIGNAL(triggered()), this, SLOT(slotCreateNewBrushPresetEngine())); } m_d->uiWdgPaintOpPresetSettings.newPresetEngineButton->setMenu(newPresetBrushEnginesMenu); // fill the list into the brush combo box sortedBrushEnginesList.push_front(KisPaintOpInfo(QString("all_options"), i18n("All"), QString(""), QIcon(emptyPixmap), 0 )); for (int m = 0; m < sortedBrushEnginesList.length(); m++) { m_d->uiWdgPaintOpPresetSettings.brushEgineComboBox->addItem(sortedBrushEnginesList[m].icon, sortedBrushEnginesList[m].name, QVariant(sortedBrushEnginesList[m].id)); } } void KisPaintOpPresetsPopup::setCurrentPaintOpId(const QString& paintOpId) { current_paintOpId = paintOpId; } QString KisPaintOpPresetsPopup::currentPaintOpId() { return current_paintOpId; } void KisPaintOpPresetsPopup::setPresetImage(const QImage& image) { m_d->uiWdgPaintOpPresetSettings.scratchPad->setPresetImage(image); saveDialog->brushPresetThumbnailWidget->setPresetImage(image); } void KisPaintOpPresetsPopup::hideEvent(QHideEvent *event) { if (m_d->ignoreHideEvents) { return; } if (m_d->detached) { m_d->detachedGeometry = window()->geometry(); } QWidget::hideEvent(event); } void KisPaintOpPresetsPopup::showEvent(QShowEvent *) { if (m_d->detached) { window()->setGeometry(m_d->detachedGeometry); } emit brushEditorShown(); } void KisPaintOpPresetsPopup::resizeEvent(QResizeEvent* event) { QWidget::resizeEvent(event); if (parentWidget()) { // Make sure resizing doesn't push this widget out of the screen QRect screenRect = QApplication::desktop()->availableGeometry(this); QRect newPositionRect = kisEnsureInRect(parentWidget()->geometry(), screenRect); parentWidget()->setGeometry(newPositionRect); } } bool KisPaintOpPresetsPopup::detached() const { return m_d->detached; } void KisPaintOpPresetsPopup::slotSwitchScratchpad(bool visible) { // hide all the internal controls except the toggle button m_d->uiWdgPaintOpPresetSettings.scratchPad->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.paintPresetIcon->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.fillGradient->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.fillLayer->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.fillSolid->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.eraseScratchPad->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.scratchpadSidebarLabel->setVisible(visible); if (visible) { m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setIcon(KisIconUtils::loadIcon("arrow-left")); } else { m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setIcon(KisIconUtils::loadIcon("arrow-right")); } KisConfig cfg(false); cfg.setScratchpadVisible(visible); } void KisPaintOpPresetsPopup::slotSwitchShowEditor(bool visible) { m_d->uiWdgPaintOpPresetSettings.brushEditorSettingsControls->setVisible(visible); } void KisPaintOpPresetsPopup::slotSwitchShowPresets(bool visible) { m_d->uiWdgPaintOpPresetSettings.presetWidget->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.presetChangeViewToolButton->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.brushEgineComboBox->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.engineFilterLabel->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.presetsSidebarLabel->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.newPresetEngineButton->setVisible(visible); m_d->uiWdgPaintOpPresetSettings.bnBlacklistPreset->setVisible(visible); // we only want a spacer to work when the toggle icon is present. Otherwise the list of presets will shrink // which is something we don't want if (visible) { m_d->uiWdgPaintOpPresetSettings.presetsSpacer->changeSize(0,0, QSizePolicy::Ignored,QSizePolicy::Ignored); m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setIcon(KisIconUtils::loadIcon("arrow-right")); } else { m_d->uiWdgPaintOpPresetSettings.presetsSpacer->changeSize(0,0, QSizePolicy::MinimumExpanding,QSizePolicy::MinimumExpanding); m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setIcon(KisIconUtils::loadIcon("arrow-left")); } } void KisPaintOpPresetsPopup::slotUpdatePaintOpFilter() { QVariant userData = m_d->uiWdgPaintOpPresetSettings.brushEgineComboBox->currentData(); // grab paintOpID from data QString filterPaintOpId = userData.toString(); if (filterPaintOpId == "all_options") { filterPaintOpId = ""; } m_d->uiWdgPaintOpPresetSettings.presetWidget->setPresetFilter(filterPaintOpId); } void KisPaintOpPresetsPopup::slotSaveBrushPreset() { // here we are assuming that people want to keep their existing preset icon. We will just update the // settings and save a new copy with the same name. // there is a dialog with save options, but we don't need to show it in this situation saveDialog->useNewBrushDialog(false); // this mostly just makes sure we keep the existing brush preset name when saving saveDialog->loadExistingThumbnail(); // This makes sure we use the existing preset icon when updating the existing brush preset saveDialog->savePreset(); // refresh the view settings so the brush doesn't appear dirty slotUpdatePresetSettings(); } void KisPaintOpPresetsPopup::slotSaveNewBrushPreset() { saveDialog->useNewBrushDialog(true); saveDialog->saveScratchPadThumbnailArea(m_d->uiWdgPaintOpPresetSettings.scratchPad->cutoutOverlay()); saveDialog->showDialog(); } void KisPaintOpPresetsPopup::slotCreateNewBrushPresetEngine() { emit createPresetFromScratch(sender()->objectName()); } void KisPaintOpPresetsPopup::updateViewSettings() { m_d->uiWdgPaintOpPresetSettings.presetWidget->smallPresetChooser->updateViewSettings(); } void KisPaintOpPresetsPopup::currentPresetChanged(KisPaintOpPresetSP preset) { if (preset) { - m_d->uiWdgPaintOpPresetSettings.presetWidget->smallPresetChooser->setCurrentResource(preset.data()); + m_d->uiWdgPaintOpPresetSettings.presetWidget->smallPresetChooser->setCurrentResource(preset); setCurrentPaintOpId(preset->paintOp().id()); } } void KisPaintOpPresetsPopup::updateThemedIcons() { m_d->uiWdgPaintOpPresetSettings.paintPresetIcon->setIcon(KisIconUtils::loadIcon("krita_tool_freehand")); m_d->uiWdgPaintOpPresetSettings.fillLayer->setIcon(KisIconUtils::loadIcon("document-new")); m_d->uiWdgPaintOpPresetSettings.fillLayer->hide(); m_d->uiWdgPaintOpPresetSettings.fillGradient->setIcon(KisIconUtils::loadIcon("krita_tool_gradient")); m_d->uiWdgPaintOpPresetSettings.fillSolid->setIcon(KisIconUtils::loadIcon("krita_tool_color_fill")); m_d->uiWdgPaintOpPresetSettings.eraseScratchPad->setIcon(KisIconUtils::loadIcon("edit-delete")); m_d->uiWdgPaintOpPresetSettings.newPresetEngineButton->setIcon(KisIconUtils::loadIcon("addlayer")); m_d->uiWdgPaintOpPresetSettings.bnBlacklistPreset->setIcon(KisIconUtils::loadIcon("deletelayer")); m_d->uiWdgPaintOpPresetSettings.reloadPresetButton->setIcon(KisIconUtils::loadIcon("updateColorize")); // refresh icon m_d->uiWdgPaintOpPresetSettings.renameBrushPresetButton->setIcon(KisIconUtils::loadIcon("dirty-preset")); // edit icon m_d->uiWdgPaintOpPresetSettings.dirtyPresetIndicatorButton->setIcon(KisIconUtils::loadIcon("warning")); m_d->uiWdgPaintOpPresetSettings.newPresetEngineButton->setIcon(KisIconUtils::loadIcon("addlayer")); m_d->uiWdgPaintOpPresetSettings.bnBlacklistPreset->setIcon(KisIconUtils::loadIcon("deletelayer")); m_d->uiWdgPaintOpPresetSettings.presetChangeViewToolButton->setIcon(KisIconUtils::loadIcon("configure")); // if we cannot see the "Preset label", we know it is not visible // maybe this can also be stored in the config like the scratchpad? if (m_d->uiWdgPaintOpPresetSettings.presetsSidebarLabel->isVisible()) { m_d->uiWdgPaintOpPresetSettings.presetsSpacer->changeSize(0,0, QSizePolicy::Ignored,QSizePolicy::Ignored); m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setIcon(KisIconUtils::loadIcon("arrow-right")); } else { m_d->uiWdgPaintOpPresetSettings.presetsSpacer->changeSize(0,0, QSizePolicy::MinimumExpanding,QSizePolicy::MinimumExpanding); m_d->uiWdgPaintOpPresetSettings.showPresetsButton->setIcon(KisIconUtils::loadIcon("arrow-left")); } // we store whether the scratchpad if visible in the config. KisConfig cfg(true); if (cfg.scratchpadVisible()) { m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setIcon(KisIconUtils::loadIcon("arrow-left")); } else { m_d->uiWdgPaintOpPresetSettings.showScratchpadButton->setIcon(KisIconUtils::loadIcon("arrow-right")); } } void KisPaintOpPresetsPopup::slotUpdatePresetSettings() { if (!m_d->resourceProvider) { return; } if (!m_d->resourceProvider->currentPreset()) { return; } // hide options on UI if we are creating a brush preset from scratch to prevent confusion if (m_d->isCreatingBrushFromScratch) { m_d->uiWdgPaintOpPresetSettings.dirtyPresetIndicatorButton->setVisible(false); m_d->uiWdgPaintOpPresetSettings.reloadPresetButton->setVisible(false); m_d->uiWdgPaintOpPresetSettings.saveBrushPresetButton->setVisible(false); m_d->uiWdgPaintOpPresetSettings.renameBrushPresetButton->setVisible(false); } else { bool isPresetDirty = m_d->resourceProvider->currentPreset()->isPresetDirty(); // don't need to reload or overwrite a clean preset m_d->uiWdgPaintOpPresetSettings.dirtyPresetIndicatorButton->setVisible(isPresetDirty); m_d->uiWdgPaintOpPresetSettings.reloadPresetButton->setVisible(isPresetDirty); m_d->uiWdgPaintOpPresetSettings.saveBrushPresetButton->setEnabled(isPresetDirty); m_d->uiWdgPaintOpPresetSettings.renameBrushPresetButton->setVisible(true); } // update live preview area in here... // don't update the live preview if the widget is not visible. if (m_d->uiWdgPaintOpPresetSettings.liveBrushPreviewView->isVisible()) { m_d->uiWdgPaintOpPresetSettings.liveBrushPreviewView->setCurrentPreset(m_d->resourceProvider->currentPreset()); m_d->uiWdgPaintOpPresetSettings.liveBrushPreviewView->updateStroke(); } } diff --git a/libs/ui/widgets/kis_paintop_presets_popup.h b/libs/ui/widgets/kis_paintop_presets_popup.h index fea64cc57d..0641dd4d39 100644 --- a/libs/ui/widgets/kis_paintop_presets_popup.h +++ b/libs/ui/widgets/kis_paintop_presets_popup.h @@ -1,147 +1,147 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2008 * Copyright (C) 2010 Lukáš Tvrdý * Copyright (C) 2011 Silvio Heinrich * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KIS_PAINTOP_PRESETS_POPUP_H #define KIS_PAINTOP_PRESETS_POPUP_H #include #include #include #include #include #include "../kis_paint_ops_model.h" #include #include #include "widgets/kis_paintop_presets_popup.h" #include "kis_favorite_resource_manager.h" class QString; class KisCanvasResourceProvider; class KoResource; /** * Popup widget for presets with built-in functionality * for adding and removing presets. */ class KisPaintOpPresetsPopup : public QWidget { Q_OBJECT public: KisPaintOpPresetsPopup(KisCanvasResourceProvider * resourceProvider, KisFavoriteResourceManager* favoriteResourceManager, KisPresetSaveWidget* savePresetWidget, QWidget * parent = 0); ~KisPaintOpPresetsPopup() override; void setPaintOpSettingsWidget(QWidget * widget); ///Image for preset preview ///@return image cut out from the scratchpad QImage cutOutOverlay(); void setPaintOpList(const QList& list); void setCurrentPaintOpId(const QString & paintOpId); /// returns the internal ID for the paint op (brush engine) QString currentPaintOpId(); ///fill the cutoutOverlay rect with the cotent of an image, used to get the image back when selecting a preset ///@param image image that will be used, should be image of an existing preset resource void setPresetImage(const QImage& image); void resizeEvent(QResizeEvent* ) override; bool detached() const; void updateViewSettings(); void currentPresetChanged(KisPaintOpPresetSP preset); KisPresetSaveWidget * saveDialog; // toggle the state when we are creating a brush from scratch void setCreatingBrushFromScratch(bool enable); protected: void contextMenuEvent(QContextMenuEvent *) override; void hideEvent(QHideEvent *) override; void showEvent(QShowEvent *) override; public Q_SLOTS: void switchDetached(bool show = true); - void resourceSelected(KoResource* resource); + void resourceSelected(KoResourceSP resource); void updateThemedIcons(); void slotUpdatePresetSettings(); void slotUpdateLodAvailability(); void slotRenameBrushActivated(); void slotRenameBrushDeactivated(); void slotSaveRenameCurrentBrush(); void slotCreateNewBrushPresetEngine(); Q_SIGNALS: void savePresetClicked(); void saveBrushPreset(); void defaultPresetClicked(); void paintopActivated(const QString& presetName); - void signalResourceSelected(KoResource* resource); + void signalResourceSelected(KoResourceSP resource); void reloadPresetClicked(); void dirtyPresetToggled(bool value); void eraserBrushSizeToggled(bool value); void eraserBrushOpacityToggled(bool value); void brushEditorShown(); void createPresetFromScratch(const QString& paintOpName); private Q_SLOTS: void slotSwitchScratchpad(bool visible); void slotResourceChanged(int key, const QVariant &value); void slotLodAvailabilityChanged(bool value); void slotLodThresholdChanged(qreal value); void slotSwitchShowEditor(bool visible); void slotUpdatePaintOpFilter(); void slotSwitchShowPresets(bool visible); void slotSaveBrushPreset(); void slotSaveNewBrushPreset(); /// we do not delete brushe presets, but blacklist them so they disappear from the interface void slotBlackListCurrentPreset(); private: struct Private; Private * const m_d; QString current_paintOpId; QList sortedBrushEnginesList; QMenu * newPresetBrushEnginesMenu; QList newBrushEngineOptions; void toggleBrushRenameUIActive(bool isRenaming); }; #endif diff --git a/libs/ui/widgets/kis_paintop_presets_save.cpp b/libs/ui/widgets/kis_paintop_presets_save.cpp index e137b9231d..9141ede41a 100644 --- a/libs/ui/widgets/kis_paintop_presets_save.cpp +++ b/libs/ui/widgets/kis_paintop_presets_save.cpp @@ -1,271 +1,271 @@ /* This file is part of the KDE project * Copyright (C) 2017 Scott Petrovic * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "widgets/kis_paintop_presets_save.h" #include #include #include #include #include #include #include "KisImportExportManager.h" #include "QDesktopServices" #include "KisResourceServerProvider.h" #include KisPresetSaveWidget::KisPresetSaveWidget(QWidget * parent) : KisPaintOpPresetSaveDialog(parent) { // this is setting the area we will "capture" for saving the brush preset. It can potentially be a different // area that the entire scratchpad brushPresetThumbnailWidget->setCutoutOverlayRect(QRect(0, 0, brushPresetThumbnailWidget->height(), brushPresetThumbnailWidget->width())); // we will default to reusing the previous preset thumbnail // have that checked by default, hide the other elements, and load the last preset image connect(clearBrushPresetThumbnailButton, SIGNAL(clicked(bool)), brushPresetThumbnailWidget, SLOT(fillDefault())); connect(loadImageIntoThumbnailButton, SIGNAL(clicked(bool)), this, SLOT(loadImageFromFile())); connect(loadScratchPadThumbnailButton, SIGNAL(clicked(bool)), this, SLOT(loadScratchpadThumbnail())); connect(loadExistingThumbnailButton, SIGNAL(clicked(bool)), this, SLOT(loadExistingThumbnail())); connect(loadIconLibraryThumbnailButton, SIGNAL(clicked(bool)), this, SLOT(loadImageFromLibrary())); connect(savePresetButton, SIGNAL(clicked(bool)), this, SLOT(savePreset())); connect(cancelButton, SIGNAL(clicked(bool)), this, SLOT(close())); } KisPresetSaveWidget::~KisPresetSaveWidget() { } void KisPresetSaveWidget::scratchPadSetup(KisCanvasResourceProvider* resourceProvider) { m_resourceProvider = resourceProvider; brushPresetThumbnailWidget->setupScratchPad(m_resourceProvider, Qt::white); } void KisPresetSaveWidget::showDialog() { setModal(true); // set the name of the current brush preset area. KisPaintOpPresetSP preset = m_resourceProvider->currentPreset(); // UI will look a bit different if we are saving a new brush if (m_useNewBrushDialog) { setWindowTitle(i18n("Save New Brush Preset")); newBrushNameTexField->setVisible(true); clearBrushPresetThumbnailButton->setVisible(true); loadImageIntoThumbnailButton->setVisible(true); currentBrushNameLabel->setVisible(false); if (preset) { newBrushNameTexField->setText(preset->name().append(" ").append(i18n("Copy"))); } } else { setWindowTitle(i18n("Save Brush Preset")); if (preset) { currentBrushNameLabel->setText(preset->name()); } newBrushNameTexField->setVisible(false); currentBrushNameLabel->setVisible(true); } brushPresetThumbnailWidget->paintPresetImage(); show(); } void KisPresetSaveWidget::loadImageFromFile() { // create a dialog to retrieve an image file. KoFileDialog dialog(0, KoFileDialog::OpenFile, "OpenDocument"); dialog.setMimeTypeFilters(KisImportExportManager::supportedMimeTypes(KisImportExportManager::Import)); dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); QString filename = dialog.filename(); // the filename() returns the entire path & file name, not just the file name if (filename != "") { // empty if "cancel" is pressed // take that file and load it into the thumbnail are const QImage imageToLoad(filename); brushPresetThumbnailWidget->fillTransparent(); // clear the background in case our new image has transparency brushPresetThumbnailWidget->paintCustomImage(imageToLoad); } } void KisPresetSaveWidget::loadScratchpadThumbnail() { brushPresetThumbnailWidget->paintCustomImage(scratchPadThumbnailArea); } void KisPresetSaveWidget::loadExistingThumbnail() { brushPresetThumbnailWidget->paintPresetImage(); } void KisPresetSaveWidget::loadImageFromLibrary() { //add dialog code here. QDialog *dlg = new QDialog(this); dlg->setWindowTitle(i18n("Preset Icon Library")); QVBoxLayout *layout = new QVBoxLayout(); dlg->setLayout(layout); KisPaintopPresetIconLibrary *libWidget = new KisPaintopPresetIconLibrary(dlg); layout->addWidget(libWidget); QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, dlg); connect(buttons, SIGNAL(accepted()), dlg, SLOT(accept())); connect(buttons, SIGNAL(rejected()), dlg, SLOT(reject())); layout->addWidget(buttons); //if dialog accepted, get image. if (dlg->exec()==QDialog::Accepted) { QImage presetImage = libWidget->getImage(); brushPresetThumbnailWidget->paintCustomImage(presetImage); } } void KisPresetSaveWidget::setFavoriteResourceManager(KisFavoriteResourceManager * favManager) { m_favoriteResourceManager = favManager; } void KisPresetSaveWidget::savePreset() { KisPaintOpPresetSP curPreset = m_resourceProvider->currentPreset(); if (!curPreset) return; m_favoriteResourceManager->setBlockUpdates(true); KisPaintOpPresetSP oldPreset = curPreset->clone(); // tags are not cloned with this oldPreset->load(); KisPaintOpPresetResourceServer * rServer = KisResourceServerProvider::instance()->paintOpPresetServer(); QString saveLocation = rServer->saveLocation(); // if we are saving a new brush, use what we type in for the input QString presetName = m_useNewBrushDialog ? newBrushNameTexField->text() : curPreset->name(); QString currentPresetFileName = saveLocation + presetName.replace(" ", "_") + curPreset->defaultFileExtension(); bool isSavingOverExistingPreset = rServer->resourceByName(presetName); // make a back up of the existing preset if we are saving over it if (isSavingOverExistingPreset) { QString currentDate = QDate::currentDate().toString(Qt::ISODate); QString currentTime = QTime::currentTime().toString(Qt::ISODate).remove(QChar(':')); QString presetFilename = saveLocation + presetName.replace(" ", "_") + "_backup_" + currentDate + "-" + currentTime + oldPreset->defaultFileExtension(); oldPreset->setFilename(presetFilename); oldPreset->setName(presetName); oldPreset->setPresetDirty(false); oldPreset->setValid(true); // add backup resource to the blacklist rServer->addResource(oldPreset); - rServer->removeResourceAndBlacklist(oldPreset.data()); + rServer->removeResourceAndBlacklist(oldPreset); QStringList tags; - tags = rServer->assignedTagsList(curPreset.data()); + tags = rServer->assignedTagsList(curPreset); Q_FOREACH (const QString & tag, tags) { - rServer->addTag(oldPreset.data(), tag); + rServer->addTag(oldPreset, tag); } } if (m_useNewBrushDialog) { KisPaintOpPresetSP newPreset = curPreset->clone(); newPreset->setFilename(currentPresetFileName); newPreset->setName(presetName); newPreset->setImage(brushPresetThumbnailWidget->cutoutOverlay()); newPreset->setPresetDirty(false); newPreset->setValid(true); // keep tags if we are saving over existing preset if (isSavingOverExistingPreset) { QStringList tags; - tags = rServer->assignedTagsList(curPreset.data()); + tags = rServer->assignedTagsList(curPreset); Q_FOREACH (const QString & tag, tags) { - rServer->addTag(newPreset.data(), tag); + rServer->addTag(newPreset, tag); } } rServer->addResource(newPreset); // trying to get brush preset to load after it is created - emit resourceSelected(newPreset.data()); + emit resourceSelected(newPreset); } else { // saving a preset that is replacing an existing one if (curPreset->filename().contains(saveLocation) == false || curPreset->filename().contains(presetName) == false) { - rServer->removeResourceAndBlacklist(curPreset.data()); + rServer->removeResourceAndBlacklist(curPreset); curPreset->setFilename(currentPresetFileName); curPreset->setName(presetName); } if (!rServer->resourceByFilename(curPreset->filename())){ //this is necessary so that we can get the preset afterwards. rServer->addResource(curPreset, false, false); - rServer->removeFromBlacklist(curPreset.data()); + rServer->removeFromBlacklist(curPreset); } if (curPreset->image().isNull()) { curPreset->setImage(brushPresetThumbnailWidget->cutoutOverlay()); } // we should not load() the brush right after saving because it will reset all our saved // eraser size and opacity values curPreset->save(); } // HACK ALERT! the server does not notify the observers // automatically, so we need to call theupdate manually! rServer->tagCategoryMembersChanged(); m_favoriteResourceManager->setBlockUpdates(false); close(); // we are done... so close the save brush dialog } void KisPresetSaveWidget::saveScratchPadThumbnailArea(QImage image) { scratchPadThumbnailArea = image; } void KisPresetSaveWidget::useNewBrushDialog(bool show) { m_useNewBrushDialog = show; } #include "moc_kis_paintop_presets_save.cpp" diff --git a/libs/ui/widgets/kis_paintop_presets_save.h b/libs/ui/widgets/kis_paintop_presets_save.h index 3185a8b478..3362087e6f 100644 --- a/libs/ui/widgets/kis_paintop_presets_save.h +++ b/libs/ui/widgets/kis_paintop_presets_save.h @@ -1,81 +1,79 @@ /* This file is part of the KDE project * Copyright (C) 2017 Scott Petrovic * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KIS_PAINTOP_PRESETS_SAVE_H #define KIS_PAINTOP_PRESETS_SAVE_H #include #include #include "ui_wdgsavebrushpreset.h" #include "kis_canvas_resource_provider.h" #include "kis_favorite_resource_manager.h" class KisPaintOpPresetSaveDialog : public QDialog , public Ui::WdgSaveBrushPreset { Q_OBJECT - - public: KisPaintOpPresetSaveDialog(QWidget* parent) : QDialog(parent) { setupUi(this); } }; class KisPresetSaveWidget : public KisPaintOpPresetSaveDialog { Q_OBJECT public: KisPresetSaveWidget(QWidget* parent); virtual ~KisPresetSaveWidget(); void showDialog(); /// determines if we should show the save as dialog (true) or save in the background (false) void useNewBrushDialog(bool show); void scratchPadSetup(KisCanvasResourceProvider* resourceProvider); void saveScratchPadThumbnailArea(const QImage image); KisCanvasResourceProvider* m_resourceProvider; void setFavoriteResourceManager(KisFavoriteResourceManager * favManager); Q_SIGNALS: - void resourceSelected(KoResource* resource); + void resourceSelected(KoResourceSP resource); public Q_SLOTS: void loadImageFromFile(); void savePreset(); void loadScratchpadThumbnail(); void loadExistingThumbnail(); void loadImageFromLibrary(); private: bool m_useNewBrushDialog; KisFavoriteResourceManager * m_favoriteResourceManager; QImage scratchPadThumbnailArea; }; #endif diff --git a/libs/ui/widgets/kis_pattern_chooser.cc b/libs/ui/widgets/kis_pattern_chooser.cc index 0131a3ed1c..b6849dfe6a 100644 --- a/libs/ui/widgets/kis_pattern_chooser.cc +++ b/libs/ui/widgets/kis_pattern_chooser.cc @@ -1,117 +1,117 @@ /* * 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_pattern_chooser.h" #include #include #include #include #include #include #include #include #include #include #include "kis_signals_blocker.h" #include "kis_global.h" #include #include #include KisPatternChooser::KisPatternChooser(QWidget *parent) : QFrame(parent) { m_lblName = new KSqueezedTextLabel(this); m_lblName->setTextElideMode(Qt::ElideLeft); KoResourceServer * rserver = KoResourceServerProvider::instance()->patternServer(); QSharedPointer adapter (new KoResourceServerAdapter(rserver)); m_itemChooser = new KoResourceItemChooser(adapter, this, true); m_itemChooser->setPreviewTiled(true); m_itemChooser->setPreviewOrientation(Qt::Horizontal); m_itemChooser->showTaggingBar(true); m_itemChooser->setSynced(true); - connect(m_itemChooser, SIGNAL(resourceSelected(KoResource*)), - this, SLOT(update(KoResource*))); + connect(m_itemChooser, SIGNAL(resourceSelected(KoResourceSP )), + this, SLOT(update(KoResourceSP ))); - connect(m_itemChooser, SIGNAL(resourceSelected(KoResource*)), - this, SIGNAL(resourceSelected(KoResource*))); + connect(m_itemChooser, SIGNAL(resourceSelected(KoResourceSP )), + this, SIGNAL(resourceSelected(KoResourceSP ))); QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); mainLayout->setMargin(0); mainLayout->addWidget(m_lblName); mainLayout->addWidget(m_itemChooser, 10); setLayout(mainLayout); } KisPatternChooser::~KisPatternChooser() { } -KoResource * KisPatternChooser::currentResource() +KoResourceSP KisPatternChooser::currentResource() { if (!m_itemChooser->currentResource()) { KoResourceServer * rserver = KoResourceServerProvider::instance()->patternServer(); if (rserver->resources().size() > 0) { KisSignalsBlocker blocker(m_itemChooser); m_itemChooser->setCurrentResource(rserver->resources().first()); } } return m_itemChooser->currentResource(); } -void KisPatternChooser::setCurrentPattern(KoResource *resource) +void KisPatternChooser::setCurrentPattern(KoResourceSP resource) { m_itemChooser->setCurrentResource(resource); } void KisPatternChooser::setCurrentItem(int row, int column) { m_itemChooser->setCurrentItem(row, column); if (currentResource()) { update(currentResource()); } } void KisPatternChooser::setPreviewOrientation(Qt::Orientation orientation) { m_itemChooser->setPreviewOrientation(orientation); } -void KisPatternChooser::update(KoResource * resource) +void KisPatternChooser::update(KoResourceSP resource) { m_lblName->setFixedWidth(m_itemChooser->width()); - KoPattern *pattern = static_cast(resource); + KoPatternSP pattern = resource.staticCast(); m_lblName->setText(QString("%1 (%2 x %3)").arg(i18n(pattern->name().toUtf8().data())).arg(pattern->width()).arg(pattern->height())); } void KisPatternChooser::setGrayscalePreview(bool grayscale) { m_itemChooser->setGrayscalePreview(grayscale); } diff --git a/libs/ui/widgets/kis_pattern_chooser.h b/libs/ui/widgets/kis_pattern_chooser.h index 462df2a9f8..9be11d029e 100644 --- a/libs/ui/widgets/kis_pattern_chooser.h +++ b/libs/ui/widgets/kis_pattern_chooser.h @@ -1,63 +1,66 @@ /* * Copyright (c) 2004 Adrian Page * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_PATTERN_CHOOSER_H_ #define KIS_PATTERN_CHOOSER_H_ #include + +#include + #include class KSqueezedTextLabel; class KoResourceItemChooser; -class KoResource; + class KRITAUI_EXPORT KisPatternChooser : public QFrame { Q_OBJECT public: KisPatternChooser(QWidget *parent = 0); ~KisPatternChooser() override; /// Gets the currently selected resource /// @returns the selected resource, 0 is no resource is selected - KoResource *currentResource(); - void setCurrentPattern(KoResource *resource); + KoResourceSP currentResource(); + void setCurrentPattern(KoResourceSP resource); void setCurrentItem(int row, int column); void setGrayscalePreview(bool grayscale); /// determines whether the preview right or below the splitter void setPreviewOrientation(Qt::Orientation orientation); Q_SIGNALS: /// Emitted when a resource was selected - void resourceSelected(KoResource *resource); + void resourceSelected(KoResourceSP resource); void updateItemSize(); private Q_SLOTS: - void update(KoResource *resource); + void update(KoResourceSP resource); private: KSqueezedTextLabel *m_lblName; KoResourceItemChooser *m_itemChooser; }; #endif // KIS_PATTERN_CHOOSER_H_ diff --git a/libs/ui/widgets/kis_preset_chooser.cpp b/libs/ui/widgets/kis_preset_chooser.cpp index 7ac85a9fb9..d3bc306812 100644 --- a/libs/ui/widgets/kis_preset_chooser.cpp +++ b/libs/ui/widgets/kis_preset_chooser.cpp @@ -1,368 +1,367 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2009 Sven Langkamp * Copyright (C) 2011 Silvio Heinrich * Copyright (C) 2011 Srikanth Tiyyagura * Copyright (c) 2011 José Luis Vergara * * 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_preset_chooser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KoResourceItemView.h" #include #include #include "KisResourceServerProvider.h" #include "kis_global.h" #include "kis_slider_spin_box.h" #include "kis_config_notifier.h" #include /// The resource item delegate for rendering the resource preview class KisPresetDelegate : public QAbstractItemDelegate { public: KisPresetDelegate(QObject * parent = 0) : QAbstractItemDelegate(parent), m_showText(false), m_useDirtyPresets(false) {} ~KisPresetDelegate() override {} /// reimplemented void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override; /// reimplemented QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex &) const override { return option.decorationSize; } void setShowText(bool showText) { m_showText = showText; } void setUseDirtyPresets(bool value) { m_useDirtyPresets = value; } private: bool m_showText; bool m_useDirtyPresets; }; void KisPresetDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { painter->save(); painter->setRenderHint(QPainter::SmoothPixmapTransform, true); if (! index.isValid()) return; KisPaintOpPreset* preset = static_cast(index.internalPointer()); QImage preview = preset->image(); if(preview.isNull()) { return; } QRect paintRect = option.rect.adjusted(1, 1, -1, -1); if (!m_showText) { painter->drawImage(paintRect.x(), paintRect.y(), preview.scaled(paintRect.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); } else { QSize pixSize(paintRect.height(), paintRect.height()); painter->drawImage(paintRect.x(), paintRect.y(), preview.scaled(pixSize, Qt::KeepAspectRatio, Qt::SmoothTransformation)); // Put an asterisk after the preset if it is dirty. This will help in case the pixmap icon is too small QString dirtyPresetIndicator = QString(""); if (m_useDirtyPresets && preset->isPresetDirty()) { dirtyPresetIndicator = QString("*"); } qreal brushSize = preset->settings()->paintOpSize(); QString brushSizeText; // Disable displayed decimal precision beyond a certain brush size if (brushSize < 100) { brushSizeText = QString::number(brushSize, 'g', 3); } else { brushSizeText = QString::number(brushSize, 'f', 0); } painter->drawText(pixSize.width() + 10, option.rect.y() + option.rect.height() - 10, brushSizeText); // brush size QString presetDisplayName = preset->name().replace("_", " "); // don't need underscores that might be part of the file name painter->drawText(pixSize.width() + 40, option.rect.y() + option.rect.height() - 10, presetDisplayName.append(dirtyPresetIndicator)); } if (m_useDirtyPresets && preset->isPresetDirty()) { const QIcon icon = KisIconUtils::loadIcon(koIconName("dirty-preset")); QPixmap pixmap = icon.pixmap(QSize(15,15)); painter->drawPixmap(paintRect.x() + 3, paintRect.y() + 3, pixmap); } if (!preset->settings() || !preset->settings()->isValid()) { const QIcon icon = KisIconUtils::loadIcon("broken-preset"); icon.paint(painter, QRect(paintRect.x() + paintRect.height() - 25, paintRect.y() + paintRect.height() - 25, 25, 25)); } if (option.state & QStyle::State_Selected) { painter->setCompositionMode(QPainter::CompositionMode_HardLight); painter->setOpacity(1.0); painter->fillRect(option.rect, option.palette.highlight()); // highlight is not strong enough to pick out preset. draw border around it. painter->setCompositionMode(QPainter::CompositionMode_SourceOver); painter->setPen(QPen(option.palette.highlight(), 4, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); QRect selectedBorder = option.rect.adjusted(2 , 2, -2, -2); // constrict the rectangle so it doesn't bleed into other presets painter->drawRect(selectedBorder); } painter->restore(); } class KisPresetProxyAdapter : public KisPaintOpPresetResourceServerAdapter { public: KisPresetProxyAdapter(KisPaintOpPresetResourceServer* resourceServer) : KisPaintOpPresetResourceServerAdapter(resourceServer) { setSortingEnabled(true); } ~KisPresetProxyAdapter() override {} - QList< KoResource* > resources() override { + QList< KoResourceSP > resources() override { - QList serverResources = + QList serverResources = KisPaintOpPresetResourceServerAdapter::resources(); if (m_paintopID.isEmpty()) { return serverResources; } - QList resources; - Q_FOREACH (KoResource *resource, serverResources) { - KisPaintOpPreset *preset = dynamic_cast(resource); - + QList resources; + Q_FOREACH (KoResourceSP resource, serverResources) { + KisPaintOpPresetSP preset = resource.dynamicCast(); if (preset && preset->paintOp().id() == m_paintopID) { resources.append(preset); } } return resources; } ///Set id for paintop to be accept by the proxy model, if not filter is set all ///presets will be shown. void setPresetFilter(const QString& paintOpId) { m_paintopID = paintOpId; invalidate(); } ///Resets the model connected to the adapter void invalidate() { emitRemovingResource(0); } QString currentPaintOpId() const { return m_paintopID; } private: QString m_paintopID; }; KisPresetChooser::KisPresetChooser(QWidget *parent, const char *name) : QWidget(parent) { setObjectName(name); QVBoxLayout * layout = new QVBoxLayout(this); layout->setMargin(0); KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); m_adapter = QSharedPointer(new KisPresetProxyAdapter(rserver)); m_chooser = new KoResourceItemChooser(m_adapter, this); m_chooser->setObjectName("ResourceChooser"); m_chooser->setColumnCount(10); m_chooser->setRowHeight(50); m_delegate = new KisPresetDelegate(this); m_chooser->setItemDelegate(m_delegate); m_chooser->setSynced(true); layout->addWidget(m_chooser); { QScroller *scroller = KisKineticScroller::createPreconfiguredScroller(this->itemChooser()->itemView()); if (scroller) { connect(scroller, SIGNAL(stateChanged(QScroller::State)), this, SLOT(slotScrollerStateChanged(QScroller::State))); } } - connect(m_chooser, SIGNAL(resourceSelected(KoResource*)), - this, SIGNAL(resourceSelected(KoResource*))); - connect(m_chooser, SIGNAL(resourceClicked(KoResource*)), - this, SIGNAL(resourceClicked(KoResource*))); + connect(m_chooser, SIGNAL(resourceSelected(KoResourceSP )), + this, SIGNAL(resourceSelected(KoResourceSP ))); + connect(m_chooser, SIGNAL(resourceClicked(KoResourceSP )), + this, SIGNAL(resourceClicked(KoResourceSP ))); m_mode = THUMBNAIL; connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(notifyConfigChanged())); notifyConfigChanged(); } KisPresetChooser::~KisPresetChooser() { } void KisPresetChooser::showButtons(bool show) { m_chooser->showButtons(show); } void KisPresetChooser::setViewMode(KisPresetChooser::ViewMode mode) { m_mode = mode; updateViewSettings(); } void KisPresetChooser::resizeEvent(QResizeEvent* event) { QWidget::resizeEvent(event); updateViewSettings(); } void KisPresetChooser::notifyConfigChanged() { KisConfig cfg(true); m_delegate->setUseDirtyPresets(cfg.useDirtyPresets()); setIconSize(cfg.presetIconSize()); updateViewSettings(); } void KisPresetChooser::updateViewSettings() { if (m_mode == THUMBNAIL) { m_chooser->setSynced(true); m_delegate->setShowText(false); } else if (m_mode == DETAIL) { m_chooser->setSynced(false); m_chooser->setColumnCount(1); m_chooser->setColumnWidth(m_chooser->width()); KoResourceItemChooserSync* chooserSync = KoResourceItemChooserSync::instance(); m_chooser->setRowHeight(chooserSync->baseLength()); m_delegate->setShowText(true); } else if (m_mode == STRIP) { m_chooser->setSynced(false); m_chooser->setRowCount(1); m_chooser->itemView()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_chooser->itemView()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // An offset of 7 keeps the cell exactly square, TODO: use constants, not hardcoded numbers m_chooser->setColumnWidth(m_chooser->viewSize().height() - 7); m_delegate->setShowText(false); } } -void KisPresetChooser::setCurrentResource(KoResource *resource) +void KisPresetChooser::setCurrentResource(KoResourceSP resource) { /** * HACK ALERT: here we use a direct call to an adapter to notify the view * that the preset might have changed its dirty state. This state * doesn't affect the filtering so the server's cache must not be * invalidated! * * Ideally, we should call some method of KoResourceServer instead, * but it seems like a bit too much effort for such a small fix. */ if (resource == currentResource()) { KisPresetProxyAdapter *adapter = static_cast(m_adapter.data()); - KisPaintOpPreset *preset = dynamic_cast(resource); + KisPaintOpPresetSP preset = resource.dynamicCast(); if (preset) { adapter->resourceChangedNoCacheInvalidation(preset); } } m_chooser->setCurrentResource(resource); } -KoResource* KisPresetChooser::currentResource() const +KoResourceSP KisPresetChooser::currentResource() const { return m_chooser->currentResource(); } void KisPresetChooser::showTaggingBar(bool show) { m_chooser->showTaggingBar(show); } KoResourceItemChooser *KisPresetChooser::itemChooser() { return m_chooser; } void KisPresetChooser::setPresetFilter(const QString& paintOpId) { KisPresetProxyAdapter *adapter = static_cast(m_adapter.data()); if (adapter->currentPaintOpId() != paintOpId) { adapter->setPresetFilter(paintOpId); updateViewSettings(); } } void KisPresetChooser::setIconSize(int newSize) { KoResourceItemChooserSync* chooserSync = KoResourceItemChooserSync::instance(); chooserSync->setBaseLength(newSize); updateViewSettings(); } int KisPresetChooser::iconSize() { KoResourceItemChooserSync* chooserSync = KoResourceItemChooserSync::instance(); return chooserSync->baseLength(); } void KisPresetChooser::saveIconSize() { // save icon size KisConfig cfg(false); cfg.setPresetIconSize(iconSize()); } void KisPresetChooser::slotScrollerStateChanged(QScroller::State state) { KisKineticScroller::updateCursor(this, state); } diff --git a/libs/ui/widgets/kis_preset_chooser.h b/libs/ui/widgets/kis_preset_chooser.h index 22fed7d71b..798524d162 100644 --- a/libs/ui/widgets/kis_preset_chooser.h +++ b/libs/ui/widgets/kis_preset_chooser.h @@ -1,96 +1,98 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (C) 2011 Silvio Heinrich * Copyright (c) 2011 José Luis Vergara * * 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_ITEM_CHOOSER_H_ #define KIS_ITEM_CHOOSER_H_ #include #include -#include + +#include #include class KoAbstractResourceServerAdapter; class KisPresetDelegate; class KoResourceItemChooser; -class KoResource; + +#include /** * A special type of item chooser that can contain extra widgets that show * more information about the currently selected item. Reimplement update() * to extract that information and fill the appropriate widgets. */ class KRITAUI_EXPORT KisPresetChooser : public QWidget { Q_OBJECT public: KisPresetChooser(QWidget *parent = 0, const char *name = 0); ~KisPresetChooser() override; enum ViewMode{ THUMBNAIL, /// Shows thumbnails DETAIL, /// Shows thumbsnails with text next to it STRIP /// Shows thumbnails arranged in a single row }; /// Sets a list of resources in the paintop list, when ever user press enter in the linedit of paintop_presets_popup Class void setViewMode(ViewMode mode); void showButtons(bool show); - void setCurrentResource(KoResource *resource); - KoResource* currentResource() const; + void setCurrentResource(KoResourceSP resource); + KoResourceSP currentResource() const; /// Sets the visibility of tagging klineEdits void showTaggingBar(bool show); KoResourceItemChooser *itemChooser(); void setPresetFilter(const QString& paintOpId); /// get the base size for the icons. Used by the slider in the view options int iconSize(); Q_SIGNALS: - void resourceSelected(KoResource *resource); - void resourceClicked(KoResource *resource); + void resourceSelected(KoResourceSP resource); + void resourceClicked(KoResourceSP resource); public Q_SLOTS: void updateViewSettings(); /// sets the icon size. Used by slider in view menu void setIconSize(int newSize); /// saves the icon size for the presets. called by the horizontal slider release event. void saveIconSize(); void slotScrollerStateChanged(QScroller::State state); private Q_SLOTS: void notifyConfigChanged(); protected: void resizeEvent(QResizeEvent* event) override; private: KoResourceItemChooser *m_chooser; KisPresetDelegate* m_delegate; ViewMode m_mode; QSharedPointer m_adapter; }; #endif // KIS_ITEM_CHOOSER_H_ diff --git a/libs/ui/widgets/kis_scratch_pad.cpp b/libs/ui/widgets/kis_scratch_pad.cpp index 4ba935a749..d106e85b8e 100644 --- a/libs/ui/widgets/kis_scratch_pad.cpp +++ b/libs/ui/widgets/kis_scratch_pad.cpp @@ -1,518 +1,518 @@ /* This file is part of the KDE project * Copyright 2010 (C) Boudewijn Rempt * Copyright 2011 (C) Dmitry Kazakov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_scratch_pad.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_config.h" #include "kis_image.h" #include "kis_undo_stores.h" #include "kis_update_scheduler.h" #include "kis_post_execution_undo_adapter.h" #include "kis_scratch_pad_event_filter.h" #include "kis_painting_information_builder.h" #include "kis_tool_freehand_helper.h" #include "kis_image_patch.h" #include "kis_canvas_widget_base.h" #include "kis_layer_projection_plane.h" #include "kis_node_graph_listener.h" class KisScratchPadNodeListener : public KisNodeGraphListener { public: KisScratchPadNodeListener(KisScratchPad *scratchPad) : m_scratchPad(scratchPad) { } void requestProjectionUpdate(KisNode *node, const QVector &rects, bool resetAnimationCache) override { KisNodeGraphListener::requestProjectionUpdate(node, rects, resetAnimationCache); QMutexLocker locker(&m_lock); Q_FOREACH (const QRect &rc, rects) { m_scratchPad->imageUpdated(rc); } } private: KisScratchPad *m_scratchPad; QMutex m_lock; }; class KisScratchPadDefaultBounds : public KisDefaultBounds { public: KisScratchPadDefaultBounds(KisScratchPad *scratchPad) : m_scratchPad(scratchPad) { } ~KisScratchPadDefaultBounds() override {} QRect bounds() const override { return m_scratchPad->imageBounds(); } private: Q_DISABLE_COPY(KisScratchPadDefaultBounds) KisScratchPad *m_scratchPad; }; KisScratchPad::KisScratchPad(QWidget *parent) : QWidget(parent) , m_toolMode(HOVERING) , m_paintLayer(0) , m_displayProfile(0) , m_resourceProvider(0) { setAutoFillBackground(false); setMouseTracking(true); m_cursor = KisCursor::load("tool_freehand_cursor.png", 5, 5); setCursor(m_cursor); KisConfig cfg(true); QImage checkImage = KisCanvasWidgetBase::createCheckersImage(cfg.checkSize()); m_checkBrush = QBrush(checkImage); // We are not supposed to use updates here, // so just set the listener to null m_updateScheduler = new KisUpdateScheduler(0); m_undoStore = new KisSurrogateUndoStore(); m_undoAdapter = new KisPostExecutionUndoAdapter(m_undoStore, m_updateScheduler); m_nodeListener = new KisScratchPadNodeListener(this); connect(this, SIGNAL(sigUpdateCanvas(QRect)), SLOT(slotUpdateCanvas(QRect)), Qt::QueuedConnection); // filter will be deleted by the QObject hierarchy m_eventFilter = new KisScratchPadEventFilter(this); m_infoBuilder = new KisPaintingInformationBuilder(); m_helper = new KisToolFreehandHelper(m_infoBuilder); m_scaleBorderWidth = 1; } KisScratchPad::~KisScratchPad() { delete m_helper; delete m_infoBuilder; delete m_undoAdapter; delete m_undoStore; delete m_updateScheduler; delete m_nodeListener; } KisScratchPad::Mode KisScratchPad::modeFromButton(Qt::MouseButton button) const { return button == Qt::NoButton ? HOVERING : button == Qt::MidButton ? PANNING : button == Qt::RightButton ? PICKING : PAINTING; } void KisScratchPad::pointerPress(KoPointerEvent *event) { if (m_toolMode != HOVERING) return; m_toolMode = modeFromButton(event->button()); if (m_toolMode == PAINTING) { beginStroke(event); event->accept(); } else if (m_toolMode == PANNING) { beginPan(event); event->accept(); } else if (m_toolMode == PICKING) { pick(event); event->accept(); } } void KisScratchPad::pointerRelease(KoPointerEvent *event) { if (modeFromButton(event->button()) != m_toolMode) return; if (m_toolMode == PAINTING) { endStroke(event); m_toolMode = HOVERING; event->accept(); } else if (m_toolMode == PANNING) { endPan(event); m_toolMode = HOVERING; event->accept(); } else if (m_toolMode == PICKING) { event->accept(); m_toolMode = HOVERING; } } void KisScratchPad::pointerMove(KoPointerEvent *event) { m_helper->cursorMoved(documentToWidget().map(event->point)); if (m_toolMode == PAINTING) { doStroke(event); event->accept(); } else if (m_toolMode == PANNING) { doPan(event); event->accept(); } else if (m_toolMode == PICKING) { pick(event); event->accept(); } } void KisScratchPad::beginStroke(KoPointerEvent *event) { KoCanvasResourceProvider *resourceManager = m_resourceProvider->resourceManager(); m_helper->initPaint(event, documentToWidget().map(event->point), resourceManager, 0, 0, m_updateScheduler, m_paintLayer, m_paintLayer->paintDevice()->defaultBounds()); } void KisScratchPad::doStroke(KoPointerEvent *event) { m_helper->paintEvent(event); } void KisScratchPad::endStroke(KoPointerEvent *event) { Q_UNUSED(event); m_helper->endPaint(); } void KisScratchPad::beginPan(KoPointerEvent *event) { setCursor(QCursor(Qt::ClosedHandCursor)); m_panDocPoint = event->point; } void KisScratchPad::doPan(KoPointerEvent *event) { QPointF docOffset = event->point - m_panDocPoint; m_translateTransform.translate(-docOffset.x(), -docOffset.y()); updateTransformations(); update(); } void KisScratchPad::endPan(KoPointerEvent *event) { Q_UNUSED(event); setCursor(m_cursor); } void KisScratchPad::pick(KoPointerEvent *event) { KoColor color; if (KisToolUtils::pickColor(color, m_paintLayer->projection(), event->point.toPoint())) { emit colorSelected(color); } } void KisScratchPad::setOnScreenResolution(qreal scaleX, qreal scaleY) { m_scaleBorderWidth = BORDER_SIZE(qMax(scaleX, scaleY)); m_scaleTransform = QTransform::fromScale(scaleX, scaleY); updateTransformations(); update(); } QTransform KisScratchPad::documentToWidget() const { return m_translateTransform.inverted() * m_scaleTransform; } QTransform KisScratchPad::widgetToDocument() const { return m_scaleTransform.inverted() * m_translateTransform; } void KisScratchPad::updateTransformations() { m_eventFilter->setWidgetToDocumentTransform(widgetToDocument()); } QRect KisScratchPad::imageBounds() const { return widgetToDocument().mapRect(rect()); } void KisScratchPad::imageUpdated(const QRect &rect) { emit sigUpdateCanvas(documentToWidget().mapRect(QRectF(rect)).toAlignedRect()); } void KisScratchPad::slotUpdateCanvas(const QRect &rect) { update(rect); } void KisScratchPad::paintEvent ( QPaintEvent * event ) { if(!m_paintLayer) return; QRectF imageRect = widgetToDocument().mapRect(QRectF(event->rect())); QRect alignedImageRect = imageRect.adjusted(-m_scaleBorderWidth, -m_scaleBorderWidth, m_scaleBorderWidth, m_scaleBorderWidth).toAlignedRect(); QPointF offset = alignedImageRect.topLeft(); m_paintLayer->projectionPlane()->recalculate(alignedImageRect, m_paintLayer); KisPaintDeviceSP projection = m_paintLayer->projection(); QImage image = projection->convertToQImage(m_displayProfile, alignedImageRect.x(), alignedImageRect.y(), alignedImageRect.width(), alignedImageRect.height(), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); QPainter gc(this); gc.fillRect(event->rect(), m_checkBrush); gc.setRenderHints(QPainter::SmoothPixmapTransform); gc.drawImage(QRectF(event->rect()), image, imageRect.translated(-offset)); QBrush brush(Qt::lightGray); QPen pen(brush, 1, Qt::DotLine); gc.setPen(pen); if (m_cutoutOverlay.isValid()) { gc.drawRect(m_cutoutOverlay); } if(!isEnabled()) { QColor color(Qt::lightGray); color.setAlphaF(0.5); QBrush disabledBrush(color); gc.fillRect(event->rect(), disabledBrush); } gc.end(); } void KisScratchPad::setupScratchPad(KisCanvasResourceProvider* resourceProvider, const QColor &defaultColor) { m_resourceProvider = resourceProvider; KisConfig cfg(true); setDisplayProfile(cfg.displayProfile(QApplication::desktop()->screenNumber(this))); connect(m_resourceProvider, SIGNAL(sigDisplayProfileChanged(const KoColorProfile*)), SLOT(setDisplayProfile(const KoColorProfile*))); connect(m_resourceProvider, SIGNAL(sigOnScreenResolutionChanged(qreal,qreal)), SLOT(setOnScreenResolution(qreal,qreal))); connect(this, SIGNAL(colorSelected(KoColor)), m_resourceProvider, SLOT(slotSetFGColor(KoColor))); m_defaultColor = KoColor(defaultColor, KoColorSpaceRegistry::instance()->rgb8()); KisPaintDeviceSP paintDevice = new KisPaintDevice(m_defaultColor.colorSpace(), "scratchpad"); m_paintLayer = new KisPaintLayer(0, "ScratchPad", OPACITY_OPAQUE_U8, paintDevice); m_paintLayer->setGraphListener(m_nodeListener); m_paintLayer->paintDevice()->setDefaultBounds(new KisScratchPadDefaultBounds(this)); fillDefault(); } void KisScratchPad::setCutoutOverlayRect(const QRect& rc) { m_cutoutOverlay = rc; } QImage KisScratchPad::cutoutOverlay() const { if(!m_paintLayer) return QImage(); KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice(); QRect rc = widgetToDocument().mapRect(m_cutoutOverlay); QImage rawImage = paintDevice->convertToQImage(0, rc.x(), rc.y(), rc.width(), rc.height(), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); QImage scaledImage = rawImage.scaled(m_cutoutOverlay.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); return scaledImage; } void KisScratchPad::setPresetImage(const QImage& image) { m_presetImage = image; } void KisScratchPad::paintCustomImage(const QImage& loadedImage) { // this is 99% copied from the normal paintPresetImage() // we don't want to save over the preset image, so we don't // want to store it in the m_presetImage if(!m_paintLayer) return; KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice(); QRect overlayRect = widgetToDocument().mapRect(m_cutoutOverlay); QRect imageRect(QPoint(), overlayRect.size()); QImage scaledImage = loadedImage.scaled(overlayRect.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); KisPaintDeviceSP device = new KisPaintDevice(paintDevice->colorSpace()); device->convertFromQImage(scaledImage, 0); KisPainter painter(paintDevice); painter.bitBlt(overlayRect.topLeft(), device, imageRect); update(); } void KisScratchPad::paintPresetImage() { if(!m_paintLayer) return; KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice(); QRect overlayRect = widgetToDocument().mapRect(m_cutoutOverlay); QRect imageRect(QPoint(), overlayRect.size()); QImage scaledImage = m_presetImage.scaled(overlayRect.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); KisPaintDeviceSP device = new KisPaintDevice(paintDevice->colorSpace()); device->convertFromQImage(scaledImage, 0); KisPainter painter(paintDevice); painter.bitBlt(overlayRect.topLeft(), device, imageRect); update(); } void KisScratchPad::setDisplayProfile(const KoColorProfile *colorProfile) { if (colorProfile) { m_displayProfile = colorProfile; QWidget::update(); } } void KisScratchPad::fillDefault() { if(!m_paintLayer) return; KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice(); paintDevice->setDefaultPixel(m_defaultColor); paintDevice->clear(); update(); } void KisScratchPad::fillTransparent() { if(!m_paintLayer) return; KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice(); QColor transQColor(0,0,0,0); KoColor transparentColor(transQColor, KoColorSpaceRegistry::instance()->rgb8()); transparentColor.setOpacity(0.0); paintDevice->setDefaultPixel(transparentColor); paintDevice->clear(); update(); } void KisScratchPad::fillGradient() { if(!m_paintLayer) return; KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice(); - KoAbstractGradient* gradient = m_resourceProvider->currentGradient(); + KoAbstractGradientSP gradient = m_resourceProvider->currentGradient(); QRect gradientRect = widgetToDocument().mapRect(rect()); paintDevice->clear(); KisGradientPainter painter(paintDevice); painter.setGradient(gradient); painter.setGradientShape(KisGradientPainter::GradientShapeLinear); painter.paintGradient(gradientRect.topLeft(), gradientRect.bottomRight(), KisGradientPainter::GradientRepeatNone, 0.2, false, gradientRect.left(), gradientRect.top(), gradientRect.width(), gradientRect.height()); update(); } void KisScratchPad::fillBackground() { if(!m_paintLayer) return; KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice(); paintDevice->setDefaultPixel(m_resourceProvider->bgColor()); paintDevice->clear(); update(); } void KisScratchPad::fillLayer() { if(!m_paintLayer) return; KisPaintDeviceSP paintDevice = m_paintLayer->paintDevice(); KisPainter painter(paintDevice); QRect sourceRect(0, 0, paintDevice->exactBounds().width(), paintDevice->exactBounds().height()); painter.bitBlt(QPoint(0, 0), m_resourceProvider->currentImage()->projection(), sourceRect); update(); } diff --git a/libs/ui/widgets/kis_stopgradient_slider_widget.cpp b/libs/ui/widgets/kis_stopgradient_slider_widget.cpp index f9e3b300eb..c45ec39604 100644 --- a/libs/ui/widgets/kis_stopgradient_slider_widget.cpp +++ b/libs/ui/widgets/kis_stopgradient_slider_widget.cpp @@ -1,363 +1,363 @@ /* * Copyright (c) 2004 Cyrille Berger * 2016 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "widgets/kis_stopgradient_slider_widget.h" #include #include #include #include #include #include #include #include #include #include #include "kis_global.h" #include "kis_debug.h" #include "krita_utils.h" KisStopGradientSliderWidget::KisStopGradientSliderWidget(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) , m_selectedStop(0) , m_drag(0) { QLinearGradient defaultGradient; - m_defaultGradient.reset(KoStopGradient::fromQGradient(&defaultGradient)); + 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.height(); } -void KisStopGradientSliderWidget::setGradientResource(KoStopGradient* gradient) +void KisStopGradientSliderWidget::setGradientResource(KoStopGradientSP gradient) { - m_gradient = gradient ? gradient : m_defaultGradient.data(); + 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::paintHandle(qreal position, const QColor &color, bool isSelected, QPainter *painter) { const QRect handlesRect = this->handlesStipeRect(); 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()); 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); } } 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; paintHandle(handlePositions[i].first, handlePositions[i].second.toQColor(), false, &painter); } if (m_selectedStop >= 0) { paintHandle(handlePositions[m_selectedStop].first, handlePositions[m_selectedStop].second.toQColor(), true, &painter); } } } int findNearestHandle(qreal t, const qreal tolerance, const QList &stops) { int result = -1; qreal minDistance = tolerance; for (int i = 0; i < stops.size(); i++) { const KoGradientStop &stop = stops[i]; const qreal distance = qAbs(t - stop.first); if (distance < minDistance) { minDistance = distance; result = i; } } return result; } void KisStopGradientSliderWidget::mousePressEvent(QMouseEvent * e) { if (!allowedClickRegion(handleClickTolerance()).contains(e->pos())) { QWidget::mousePressEvent(e); return; } const QRect handlesRect = this->handlesStipeRect(); const qreal t = (qreal(e->x()) - handlesRect.x()) / handlesRect.width(); const QList stops = m_gradient->stops(); const int clickedStop = findNearestHandle(t, qreal(handleClickTolerance()) / handlesRect.width(), stops); if (clickedStop >= 0) { if (m_selectedStop != clickedStop) { m_selectedStop = clickedStop; emit sigSelectedStop(m_selectedStop); } m_drag = true; } else { insertStop(qBound(0.0, t, 1.0)); m_drag = true; } update(); updateCursor(e->pos()); } void KisStopGradientSliderWidget::mouseReleaseEvent(QMouseEvent * e) { Q_UNUSED(e); m_drag = false; updateCursor(e->pos()); } int getNewInsertPosition(const KoGradientStop &stop, const QList &stops) { int result = 0; for (int i = 0; i < stops.size(); i++) { if (stop.first <= stops[i].first) break; result = i + 1; } return result; } void KisStopGradientSliderWidget::mouseMoveEvent(QMouseEvent * e) { updateCursor(e->pos()); if (m_drag) { const QRect handlesRect = this->handlesStipeRect(); double t = (qreal(e->x()) - handlesRect.x()) / handlesRect.width(); QList stops = m_gradient->stops(); if (t < -0.1 || t > 1.1) { if (stops.size() > 2 && m_selectedStop >= 0) { m_removedStop = stops[m_selectedStop]; stops.removeAt(m_selectedStop); m_selectedStop = -1; } } else { if (m_selectedStop < 0) { m_removedStop.first = qBound(0.0, t, 1.0); const int newPos = getNewInsertPosition(m_removedStop, stops); stops.insert(newPos, m_removedStop); m_selectedStop = newPos; } else { KoGradientStop draggedStop = stops[m_selectedStop]; draggedStop.first = qBound(0.0, t, 1.0); stops.removeAt(m_selectedStop); const int newPos = getNewInsertPosition(draggedStop, stops); stops.insert(newPos, draggedStop); m_selectedStop = newPos; } } m_gradient->setStops(stops); emit sigSelectedStop(m_selectedStop); update(); } else { QWidget::mouseMoveEvent(e); } } void KisStopGradientSliderWidget::updateCursor(const QPoint &pos) { const bool isInAllowedRegion = allowedClickRegion(handleClickTolerance()).contains(pos); QCursor currentCursor; if (isInAllowedRegion) { const QRect handlesRect = this->handlesStipeRect(); const qreal t = (qreal(pos.x()) - handlesRect.x()) / handlesRect.width(); const QList stops = m_gradient->stops(); const int clickedStop = findNearestHandle(t, qreal(handleClickTolerance()) / handlesRect.width(), stops); if (clickedStop >= 0) { currentCursor = m_drag ? Qt::ClosedHandCursor : Qt::OpenHandCursor; } } if (currentCursor.shape() != Qt::ArrowCursor) { setCursor(currentCursor); } else { unsetCursor(); } } void KisStopGradientSliderWidget::insertStop(double t) { KIS_ASSERT_RECOVER(t >= 0 && t <= 1.0 ) { t = qBound(0.0, t, 1.0); } QList stops = m_gradient->stops(); KoColor color; m_gradient->colorAt(color, t); const KoGradientStop stop(t, color); const int newPos = getNewInsertPosition(stop, stops); stops.insert(newPos, stop); m_gradient->setStops(stops); m_selectedStop = newPos; emit sigSelectedStop(m_selectedStop); } QRect KisStopGradientSliderWidget::sliderRect() const { return QRect(QPoint(), size()).adjusted(m_handleSize.width(), 1, -m_handleSize.width(), -1); } QRect KisStopGradientSliderWidget::gradientStripeRect() const { const QRect rc = sliderRect(); return rc.adjusted(0, 0, 0, -m_handleSize.height()); } QRect KisStopGradientSliderWidget::handlesStipeRect() const { const QRect rc = sliderRect(); return rc.adjusted(0, rc.height() - m_handleSize.height(), 0, 0); } QRegion KisStopGradientSliderWidget::allowedClickRegion(int tolerance) const { QRegion result; result += sliderRect(); result += handlesStipeRect().adjusted(-tolerance, 0, tolerance, 0); 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). expandedTo(QApplication::globalStrut())); return sz.height() + m_handleSize.height(); } QSize KisStopGradientSliderWidget::sizeHint() const { const int h = minimalHeight(); return QSize(2 * h, h); } QSize KisStopGradientSliderWidget::minimumSizeHint() const { const int h = minimalHeight(); return QSize(h, h); } diff --git a/libs/ui/widgets/kis_stopgradient_slider_widget.h b/libs/ui/widgets/kis_stopgradient_slider_widget.h index f00d7f83c4..9b1663b15f 100644 --- a/libs/ui/widgets/kis_stopgradient_slider_widget.h +++ b/libs/ui/widgets/kis_stopgradient_slider_widget.h @@ -1,82 +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(KoStopGradient* gradient); + void setGradientResource(KoStopGradientSP gradient); int selectedStop(); void setSelectedStop(int selected); QSize sizeHint() const override; QSize minimumSizeHint() const override; Q_SIGNALS: void sigSelectedStop(int stop); protected: void mousePressEvent(QMouseEvent * e) override; void mouseReleaseEvent(QMouseEvent * e) override; void mouseMoveEvent(QMouseEvent * e) override; private Q_SLOTS: void updateHandleSize(); private: void insertStop(double t); QRect sliderRect() const; QRect gradientStripeRect() const; QRect handlesStipeRect() const; QRegion allowedClickRegion(int tolerance) const; void updateCursor(const QPoint &pos); void paintHandle(qreal position, const QColor &color, bool isSelected, QPainter *painter); int handleClickTolerance() const; int minimalHeight() const; private: - QScopedPointer m_defaultGradient; - KoStopGradient* m_gradient; + KoStopGradientSP m_defaultGradient; + KoStopGradientSP m_gradient; int m_selectedStop; KoGradientStop m_removedStop; bool m_drag; QSize m_handleSize; }; #endif diff --git a/libs/ui/widgets/kis_workspace_chooser.cpp b/libs/ui/widgets/kis_workspace_chooser.cpp index 2d372d0775..696e7afb5a 100644 --- a/libs/ui/widgets/kis_workspace_chooser.cpp +++ b/libs/ui/widgets/kis_workspace_chooser.cpp @@ -1,236 +1,235 @@ /* This file is part of the KDE project * Copyright (C) 2011 Sven Langkamp * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_workspace_chooser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisResourceServerProvider.h" #include "kis_workspace_resource.h" #include "KisViewManager.h" #include #include #include #include #include #include class KisWorkspaceDelegate : public QAbstractItemDelegate { public: KisWorkspaceDelegate(QObject * parent = 0) : QAbstractItemDelegate(parent) {} ~KisWorkspaceDelegate() override {} /// reimplemented void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override; /// reimplemented QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex &) const override { return option.decorationSize; } }; void KisWorkspaceDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { if (!index.isValid()) return; - KoResource* workspace = static_cast(index.internalPointer()); + KoResourceSP workspace = KoResourceSP(static_cast(index.internalPointer())); QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) ? QPalette::Active : QPalette::Disabled; QPalette::ColorRole cr = (option.state & QStyle::State_Selected) ? QPalette::HighlightedText : QPalette::Text; painter->setPen(option.palette.color(cg, cr)); if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, option.palette.highlight()); } else { painter->fillRect(option.rect, option.palette.base()); } painter->drawText(option.rect.x() + 5, option.rect.y() + painter->fontMetrics().ascent() + 5, workspace->name()); } KisWorkspaceChooser::KisWorkspaceChooser(KisViewManager * view, QWidget* parent): QWidget(parent), m_view(view) { KoResourceServer * workspaceServer = KisResourceServerProvider::instance()->workspaceServer(); QSharedPointer workspaceAdapter(new KoResourceServerAdapter(workspaceServer)); KoResourceServer * windowLayoutServer = KisResourceServerProvider::instance()->windowLayoutServer(); QSharedPointer windowLayoutAdapter(new KoResourceServerAdapter(windowLayoutServer)); m_layout = new QGridLayout(this); m_workspaceWidgets = createChooserWidgets(workspaceAdapter, i18n("Workspaces")); m_windowLayoutWidgets = createChooserWidgets(windowLayoutAdapter, i18n("Window layouts")); - connect(m_workspaceWidgets.itemChooser, SIGNAL(resourceSelected(KoResource*)), - this, SLOT(workspaceSelected(KoResource*))); + connect(m_workspaceWidgets.itemChooser, SIGNAL(resourceSelected(KoResourceSP )), + this, SLOT(workspaceSelected(KoResourceSP ))); connect(m_workspaceWidgets.saveButton, SIGNAL(clicked(bool)), this, SLOT(slotSaveWorkspace())); - connect(m_windowLayoutWidgets.itemChooser, SIGNAL(resourceSelected(KoResource*)), - this, SLOT(windowLayoutSelected(KoResource*))); + connect(m_windowLayoutWidgets.itemChooser, SIGNAL(resourceSelected(KoResourceSP )), + this, SLOT(windowLayoutSelected(KoResourceSP ))); connect(m_windowLayoutWidgets.saveButton, SIGNAL(clicked(bool)), this, SLOT(slotSaveWindowLayout())); } KisWorkspaceChooser::ChooserWidgets KisWorkspaceChooser::createChooserWidgets(QSharedPointer adapter, const QString &title) { ChooserWidgets widgets; QLabel *titleLabel = new QLabel(this); QFont titleFont; titleFont.setBold(true); titleLabel->setFont(titleFont); titleLabel->setText(title); widgets.itemChooser = new KoResourceItemChooser(adapter, this); widgets.itemChooser->setItemDelegate(new KisWorkspaceDelegate(this)); widgets.itemChooser->setFixedSize(250, 250); widgets.itemChooser->setRowHeight(30); widgets.itemChooser->setColumnCount(1); widgets.itemChooser->showTaggingBar(false); widgets.saveButton = new QPushButton(i18n("Save")); widgets.nameEdit = new QLineEdit(this); widgets.nameEdit->setPlaceholderText(i18n("Insert name")); widgets.nameEdit->setClearButtonEnabled(true); int firstRow = m_layout->rowCount(); m_layout->addWidget(titleLabel, firstRow, 0, 1, 2); m_layout->addWidget(widgets.itemChooser, firstRow + 1, 0, 1, 2); m_layout->addWidget(widgets.nameEdit, firstRow + 2, 0, 1, 1); m_layout->addWidget(widgets.saveButton, firstRow + 2, 1, 1, 1); return widgets; } KisWorkspaceChooser::~KisWorkspaceChooser() { } void KisWorkspaceChooser::slotSaveWorkspace() { if (!m_view->qtMainWindow()) { return; } KoResourceServer * rserver = KisResourceServerProvider::instance()->workspaceServer(); - KisWorkspaceResource* workspace = new KisWorkspaceResource(QString()); + KisWorkspaceResourceSP workspace(new KisWorkspaceResource(QString())); workspace->setDockerState(m_view->qtMainWindow()->saveState()); m_view->resourceProvider()->notifySavingWorkspace(workspace); workspace->setValid(true); QString saveLocation = rserver->saveLocation(); QString name = m_workspaceWidgets.nameEdit->text(); bool newName = false; if(name.isEmpty()) { newName = true; name = i18n("Workspace"); } QFileInfo fileInfo(saveLocation + name + workspace->defaultFileExtension()); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(saveLocation + name + QString("%1").arg(i) + workspace->defaultFileExtension()); i++; } workspace->setFilename(fileInfo.filePath()); if(newName) { name = i18n("Workspace %1", i); } workspace->setName(name); rserver->addResource(workspace); } -void KisWorkspaceChooser::workspaceSelected(KoResource *resource) +void KisWorkspaceChooser::workspaceSelected(KoResourceSP resource) { if (!m_view->qtMainWindow()) { return; } - KisWorkspaceResource* workspace = static_cast(resource); + KisWorkspaceResourceSP workspace = resource.staticCast(); KisMainWindow *mainWindow = qobject_cast(m_view->qtMainWindow()); mainWindow->restoreWorkspace(workspace); - } void KisWorkspaceChooser::slotSaveWindowLayout() { KisMainWindow *thisWindow = qobject_cast(m_view->qtMainWindow()); if (!thisWindow) return; KisNewWindowLayoutDialog dlg; dlg.setName(m_windowLayoutWidgets.nameEdit->text()); dlg.exec(); if (dlg.result() != QDialog::Accepted) return; QString name = dlg.name(); bool showImageInAllWindows = dlg.showImageInAllWindows(); bool primaryWorkspaceFollowsFocus = dlg.primaryWorkspaceFollowsFocus(); - auto *layout = KisWindowLayoutResource::fromCurrentWindows(name, KisPart::instance()->mainWindows(), showImageInAllWindows, primaryWorkspaceFollowsFocus, thisWindow); + KisWindowLayoutResourceSP layout = KisWindowLayoutResource::fromCurrentWindows(name, KisPart::instance()->mainWindows(), showImageInAllWindows, primaryWorkspaceFollowsFocus, thisWindow); layout->setValid(true); KisWindowLayoutManager::instance()->setShowImageInAllWindowsEnabled(showImageInAllWindows); KisWindowLayoutManager::instance()->setPrimaryWorkspaceFollowsFocus(primaryWorkspaceFollowsFocus, thisWindow->id()); KoResourceServer * rserver = KisResourceServerProvider::instance()->windowLayoutServer(); QString saveLocation = rserver->saveLocation(); bool newName = false; if (name.isEmpty()) { newName = true; name = i18n("Window Layout"); } QFileInfo fileInfo(saveLocation + name + layout->defaultFileExtension()); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(saveLocation + name + QString("%1").arg(i) + layout->defaultFileExtension()); i++; } layout->setFilename(fileInfo.filePath()); if (newName) { name = i18n("Window Layout %1", i); } layout->setName(name); rserver->addResource(layout); } -void KisWorkspaceChooser::windowLayoutSelected(KoResource * resource) +void KisWorkspaceChooser::windowLayoutSelected(KoResourceSP resource) { - auto *layout = static_cast(resource); + KisWindowLayoutResourceSP layout = resource.staticCast(); layout->applyLayout(); } diff --git a/libs/ui/widgets/kis_workspace_chooser.h b/libs/ui/widgets/kis_workspace_chooser.h index 645b5001cc..caf7a5cfee 100644 --- a/libs/ui/widgets/kis_workspace_chooser.h +++ b/libs/ui/widgets/kis_workspace_chooser.h @@ -1,65 +1,66 @@ /* This file is part of the KDE project * Copyright (C) 2011 Sven Langkamp * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KIS_WORKSPACE_CHOOSER_H #define KIS_WORKSPACE_CHOOSER_H #include +#include class QLineEdit; class QPushButton; class QGridLayout; class KoResourceItemChooser; class KisViewManager; -class KoResource; + class KoAbstractResourceServerAdapter; class KisWorkspaceChooser : public QWidget { Q_OBJECT public: KisWorkspaceChooser(KisViewManager * view, QWidget* parent = 0); ~KisWorkspaceChooser() override; private Q_SLOTS: void slotSaveWorkspace(); - void workspaceSelected( KoResource * resource ); + void workspaceSelected( KoResourceSP resource ); void slotSaveWindowLayout(); - void windowLayoutSelected( KoResource * resource ); + void windowLayoutSelected( KoResourceSP resource ); private: struct ChooserWidgets { KoResourceItemChooser *itemChooser; QLineEdit *nameEdit; QPushButton *saveButton; }; KisViewManager *m_view; QGridLayout* m_layout; ChooserWidgets m_workspaceWidgets; ChooserWidgets m_windowLayoutWidgets; ChooserWidgets createChooserWidgets(QSharedPointer adapter, const QString &title); }; #endif // KIS_WORKSPACE_CHOOSER_H diff --git a/libs/widgets/KisColorsetChooser.h b/libs/widgets/KisColorsetChooser.h index f51cdda0f6..be15ce82ad 100644 --- a/libs/widgets/KisColorsetChooser.h +++ b/libs/widgets/KisColorsetChooser.h @@ -1,55 +1,55 @@ /* This file is part of the KDE project * Copyright (C) 2013 Sven Langkamp * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KIS_COLORSET_CHOOSER_H #define KIS_COLORSET_CHOOSER_H #include class QSpinBox; class KoColorSet; class QLineEdit; class KoResourceItemChooser; class KoResource; #include "kritawidgets_export.h" class KRITAWIDGETS_EXPORT KisColorsetChooser : public QWidget { Q_OBJECT public: KisColorsetChooser(QWidget* parent = 0); ~KisColorsetChooser() override; Q_SIGNALS: - void paletteSelected(KoColorSet* colorSet); + void paletteSelected(KoColorSetSP colorSet); private Q_SLOTS: - void resourceSelected(KoResource* resource); + void resourceSelected(KoResourceSP resource); void slotSave(); private: KoResourceItemChooser * m_itemChooser; QLineEdit* m_nameEdit; QSpinBox* m_columnEdit; }; #endif // COLORSET_CHOOSER_H diff --git a/libs/widgets/KisDlgInternalColorSelector.cpp b/libs/widgets/KisDlgInternalColorSelector.cpp index d7a5480311..71f64ec97d 100644 --- a/libs/widgets/KisDlgInternalColorSelector.cpp +++ b/libs/widgets/KisDlgInternalColorSelector.cpp @@ -1,344 +1,344 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include "KoColorSpaceRegistry.h" #include #include #include #include #include #include #include "kis_signal_compressor.h" #include "KoColorDisplayRendererInterface.h" #include "kis_spinbox_color_selector.h" #include "KisDlgInternalColorSelector.h" #include "ui_WdgDlgInternalColorSelector.h" #include "kis_config_notifier.h" #include "kis_color_input.h" #include "kis_icon_utils.h" #include "squeezedcombobox.h" std::function KisDlgInternalColorSelector::s_screenColorPickerFactory = 0; struct KisDlgInternalColorSelector::Private { bool allowUpdates = true; KoColor currentColor; KoColor previousColor; KoColor sRGB = KoColor(KoColorSpaceRegistry::instance()->rgb8()); const KoColorSpace *currentColorSpace; bool lockUsedCS = false; bool chooseAlpha = false; KisSignalCompressor *compressColorChanges; const KoColorDisplayRendererInterface *displayRenderer; KisHexColorInput *hexColorInput = 0; KisPaletteModel *paletteModel = 0; KisPaletteListWidget *paletteChooser = 0; KisScreenColorPickerBase *screenColorPicker = 0; }; KisDlgInternalColorSelector::KisDlgInternalColorSelector(QWidget *parent, KoColor color, Config config, const QString &caption, const KoColorDisplayRendererInterface *displayRenderer) : QDialog(parent) , m_d(new Private) { setModal(config.modal); setFocusPolicy(Qt::ClickFocus); m_ui = new Ui_WdgDlgInternalColorSelector(); m_ui->setupUi(this); setWindowTitle(caption); m_d->currentColor = color; m_d->currentColorSpace = m_d->currentColor.colorSpace(); m_d->displayRenderer = displayRenderer; m_ui->spinboxselector->slotSetColor(color); connect(m_ui->spinboxselector, SIGNAL(sigNewColor(KoColor)), this, SLOT(slotColorUpdated(KoColor))); m_ui->visualSelector->slotSetColor(color); m_ui->visualSelector->setDisplayRenderer(displayRenderer); m_ui->visualSelector->setConfig(false, config.modal); if (config.visualColorSelector) { connect(m_ui->visualSelector, SIGNAL(sigNewColor(KoColor)), this, SLOT(slotColorUpdated(KoColor))); connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), m_ui->visualSelector, SLOT(configurationChanged())); } else { m_ui->visualSelector->hide(); } m_d->paletteChooser = new KisPaletteListWidget(this); m_d->paletteModel = new KisPaletteModel(this); m_ui->bnPaletteChooser->setIcon(KisIconUtils::loadIcon("hi16-palette_library")); m_ui->paletteBox->setPaletteModel(m_d->paletteModel); m_ui->paletteBox->setDisplayRenderer(displayRenderer); m_ui->cmbNameList->setCompanionView(m_ui->paletteBox); connect(m_d->paletteChooser, SIGNAL(sigPaletteSelected(KoColorSet*)), this, SLOT(slotChangePalette(KoColorSet*))); connect(m_ui->cmbNameList, SIGNAL(sigColorSelected(KoColor)), SLOT(slotColorUpdated(KoColor))); // For some bizare reason, the modal dialog doesn't like having the colorset set, so let's not. if (config.paletteBox) { //TODO: Add disable signal as well. Might be not necessary...? KConfigGroup cfg(KSharedConfig::openConfig()->group("")); QString paletteName = cfg.readEntry("internal_selector_active_color_set", QString()); KoResourceServer* rServer = KoResourceServerProvider::instance()->paletteServer(); - KoColorSet *savedPal = rServer->resourceByName(paletteName); + KoColorSetSP savedPal = rServer->resourceByName(paletteName); if (savedPal) { this->slotChangePalette(savedPal); } else { if (rServer->resources().count()) { savedPal = rServer->resources().first(); if (savedPal) { this->slotChangePalette(savedPal); } } } connect(m_ui->paletteBox, SIGNAL(sigColorSelected(KoColor)), this, SLOT(slotColorUpdated(KoColor))); m_ui->bnPaletteChooser->setPopupWidget(m_d->paletteChooser); } else { m_ui->paletteBox->setEnabled(false); m_ui->cmbNameList->setEnabled(false); m_ui->bnPaletteChooser->setEnabled(false); } if (config.prevNextButtons) { m_ui->currentColor->setColor(m_d->currentColor); m_ui->currentColor->setDisplayRenderer(displayRenderer); m_ui->previousColor->setColor(m_d->currentColor); m_ui->previousColor->setDisplayRenderer(displayRenderer); connect(m_ui->previousColor, SIGNAL(triggered(KoColorPatch*)), SLOT(slotSetColorFromPatch(KoColorPatch*))); } else { m_ui->currentColor->hide(); m_ui->previousColor->hide(); } if (config.hexInput) { m_d->sRGB.fromKoColor(m_d->currentColor); m_d->hexColorInput = new KisHexColorInput(this, &m_d->sRGB); m_d->hexColorInput->update(); connect(m_d->hexColorInput, SIGNAL(updated()), SLOT(slotSetColorFromHex())); m_ui->rightPane->addWidget(m_d->hexColorInput); m_d->hexColorInput->setToolTip(i18n("This is a hexcode input, for webcolors. It can only get colors in the sRGB space.")); } // KisScreenColorPicker is in the kritaui module, so dependency inversion is used to access it. m_ui->screenColorPickerWidget->setLayout(new QHBoxLayout(m_ui->screenColorPickerWidget)); if (s_screenColorPickerFactory) { m_d->screenColorPicker = s_screenColorPickerFactory(m_ui->screenColorPickerWidget); m_ui->screenColorPickerWidget->layout()->addWidget(m_d->screenColorPicker); if (config.screenColorPicker) { connect(m_d->screenColorPicker, SIGNAL(sigNewColorPicked(KoColor)),this, SLOT(slotColorUpdated(KoColor))); } else { m_d->screenColorPicker->hide(); } } connect(this, SIGNAL(signalForegroundColorChosen(KoColor)), this, SLOT(slotLockSelector())); m_d->compressColorChanges = new KisSignalCompressor(100 /* ms */, KisSignalCompressor::POSTPONE, this); connect(m_d->compressColorChanges, SIGNAL(timeout()), this, SLOT(endUpdateWithNewColor())); connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject())); connect(this, SIGNAL(finished(int)), SLOT(slotFinishUp())); } KisDlgInternalColorSelector::~KisDlgInternalColorSelector() { delete m_ui; } void KisDlgInternalColorSelector::slotColorUpdated(KoColor newColor) { //if the update did not come from this selector... if (m_d->allowUpdates || QObject::sender() == this->parent()) { if (m_d->lockUsedCS){ newColor.convertTo(m_d->currentColorSpace); m_d->currentColor = newColor; } else { m_d->currentColor = newColor; } updateAllElements(QObject::sender()); } } void KisDlgInternalColorSelector::slotSetColorFromPatch(KoColorPatch *patch) { slotColorUpdated(patch->color()); } void KisDlgInternalColorSelector::colorSpaceChanged(const KoColorSpace *cs) { if (cs == m_d->currentColorSpace) { return; } m_d->currentColorSpace = KoColorSpaceRegistry::instance()->colorSpace(cs->colorModelId().id(), cs->colorDepthId().id(), cs->profile()); m_ui->spinboxselector->slotSetColorSpace(m_d->currentColorSpace); m_ui->visualSelector->slotsetColorSpace(m_d->currentColorSpace); } void KisDlgInternalColorSelector::lockUsedColorSpace(const KoColorSpace *cs) { colorSpaceChanged(cs); m_d->lockUsedCS = true; } void KisDlgInternalColorSelector::setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer) { if (displayRenderer) { m_d->displayRenderer = displayRenderer; m_ui->visualSelector->setDisplayRenderer(displayRenderer); m_ui->currentColor->setDisplayRenderer(displayRenderer); m_ui->previousColor->setDisplayRenderer(displayRenderer); m_ui->paletteBox->setDisplayRenderer(displayRenderer); } else { m_d->displayRenderer = KoDumbColorDisplayRenderer::instance(); } } KoColor KisDlgInternalColorSelector::getModalColorDialog(const KoColor color, QWidget* parent, QString caption) { Config config = Config(); KisDlgInternalColorSelector dialog(parent, color, config, caption); dialog.setPreviousColor(color); dialog.exec(); return dialog.getCurrentColor(); } KoColor KisDlgInternalColorSelector::getCurrentColor() { return m_d->currentColor; } void KisDlgInternalColorSelector::chooseAlpha(bool chooseAlpha) { m_d->chooseAlpha = chooseAlpha; } void KisDlgInternalColorSelector::slotConfigurationChanged() { //m_d->canvas->displayColorConverter()-> //slotColorSpaceChanged(m_d->canvas->image()->colorSpace()); } void KisDlgInternalColorSelector::slotLockSelector() { m_d->allowUpdates = false; } void KisDlgInternalColorSelector::setPreviousColor(KoColor c) { m_d->previousColor = c; } void KisDlgInternalColorSelector::reject() { slotColorUpdated(m_d->previousColor); QDialog::reject(); } void KisDlgInternalColorSelector::updateAllElements(QObject *source) { //update everything!!! if (source != m_ui->spinboxselector) { m_ui->spinboxselector->slotSetColor(m_d->currentColor); } if (source != m_ui->visualSelector) { m_ui->visualSelector->slotSetColor(m_d->currentColor); } if (source != m_d->hexColorInput) { m_d->sRGB.fromKoColor(m_d->currentColor); m_d->hexColorInput->update(); } if (source != m_ui->paletteBox) { m_ui->paletteBox->selectClosestColor(m_d->currentColor); } m_ui->previousColor->setColor(m_d->previousColor); m_ui->currentColor->setColor(m_d->currentColor); if (source != this->parent()) { emit(signalForegroundColorChosen(m_d->currentColor)); m_d->compressColorChanges->start(); } if (m_d->screenColorPicker) { m_d->screenColorPicker->updateIcons(); } } void KisDlgInternalColorSelector::endUpdateWithNewColor() { m_d->allowUpdates = true; } void KisDlgInternalColorSelector::focusInEvent(QFocusEvent *) { //setPreviousColor(); } void KisDlgInternalColorSelector::slotFinishUp() { setPreviousColor(m_d->currentColor); KConfigGroup cfg(KSharedConfig::openConfig()->group("")); if (m_d->paletteModel) { if (m_d->paletteModel->colorSet()) { cfg.writeEntry("internal_selector_active_color_set", m_d->paletteModel->colorSet()->name()); } } } void KisDlgInternalColorSelector::slotSetColorFromHex() { slotColorUpdated(m_d->sRGB); } -void KisDlgInternalColorSelector::slotChangePalette(KoColorSet *set) +void KisDlgInternalColorSelector::slotChangePalette(KoColorSetSP set) { if (!set) { return; } m_d->paletteModel->setPalette(set); } void KisDlgInternalColorSelector::showEvent(QShowEvent *event) { updateAllElements(0); QDialog::showEvent(event); } diff --git a/libs/widgets/KisDlgInternalColorSelector.h b/libs/widgets/KisDlgInternalColorSelector.h index f703182557..ff55bb3ae7 100644 --- a/libs/widgets/KisDlgInternalColorSelector.h +++ b/libs/widgets/KisDlgInternalColorSelector.h @@ -1,194 +1,194 @@ /* * Copyright (C) Wolthera van Hovell tot Westerflier , (C) 2016 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KISDLGINTERNALCOLORSELECTOR_H #define KISDLGINTERNALCOLORSELECTOR_H #include "kritawidgets_export.h" #include "KoColor.h" #include "KoColorSpace.h" #include "KoColorDisplayRendererInterface.h" #include "KoColorSet.h" #include #include "KisScreenColorPickerBase.h" #include "ui_WdgDlgInternalColorSelector.h" /** * @brief The KisInternalColorSelector class * * A non-modal color selector dialog that is not a plugin and can thus be used for filters. */ class KRITAWIDGETS_EXPORT KisDlgInternalColorSelector : public QDialog { Q_OBJECT static std::function s_screenColorPickerFactory; public: static void setScreenColorPickerFactory(std::function f) { s_screenColorPickerFactory = f; } struct Config { Config() : modal(true), visualColorSelector(true), paletteBox(true), screenColorPicker(true), prevNextButtons(true), hexInput(true), useAlpha(false){} bool modal; bool visualColorSelector; bool paletteBox; bool screenColorPicker; bool prevNextButtons; bool hexInput; bool useAlpha; }; KisDlgInternalColorSelector(QWidget* parent, KoColor color, Config config, const QString &caption, const KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance()); ~KisDlgInternalColorSelector() override; /** * @brief slotColorSpaceChanged * Color space has changed, use this dialog to change the colorspace. */ void colorSpaceChanged(const KoColorSpace *cs); /** * @brief lockUsedColorSpace * Lock the used colorspace of this selector. * @param cs */ void lockUsedColorSpace(const KoColorSpace *cs); /** * @brief setDisplayRenderer * Set the display renderer. This is necessary for HDR color manage support. * @param displayRenderer */ void setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer); /** * @brief getModalColorDialog * Execute this dialog modally. The function returns * the KoColor you want. * @param color - The current color. Make sure this is in the color space you want your * end color to be in. * @param chooseAlpha - Whether or not the alpha-choosing functionality should be used. */ static KoColor getModalColorDialog(const KoColor color, QWidget* parent = Q_NULLPTR, QString caption = QString()); /** * @brief getCurrentColor * @return gives currently active color; */ KoColor getCurrentColor(); void chooseAlpha(bool chooseAlpha); Q_SIGNALS: /** * @brief signalForegroundColorChosen * The most important signal. This will sent out when a color has been picked from the selector. * There will be a small delay to make sure that the selector causes too many updates. * * Do not connect this to slotColorUpdated. * @param color The new color chosen */ void signalForegroundColorChosen(KoColor color); public Q_SLOTS: /** * @brief slotColorUpdated * Very important slot. Is connected to krita's resources to make sure it has * the currently active color. It's very important that this function is able to understand * when the signal came from itself. * @param newColor This is the new color. */ void slotColorUpdated(KoColor newColor); /** * @brief slotSetColorFromPatch * update current color from kocolorpatch. * @param patch */ void slotSetColorFromPatch(KoColorPatch* patch); /** * @brief setPreviousColor * set the previous color. */ void setPreviousColor(KoColor c); void reject() override; private Q_SLOTS: /** * @brief slotLockSelector * This slot will prevent the color from being updated. */ void slotLockSelector(); /** * @brief slotConfigurationChanged * Wrapper slot for changes to the colorspace. */ void slotConfigurationChanged(); void endUpdateWithNewColor(); /** * @brief slotFinishUp * This is called when the selector is closed, for saving the current palette. */ void slotFinishUp(); /** * @brief slotSetColorFromHex * Update from the hex color input. */ void slotSetColorFromHex(); - void slotChangePalette(KoColorSet *set); + void slotChangePalette(KoColorSetSP set); protected: void showEvent(QShowEvent *event) override; private: void focusInEvent(QFocusEvent *) override; /** * @brief updateAllElements * Updates each widget with the new element, and if it's responsible for the update sents * a signal out that there's a new color. */ void updateAllElements(QObject *source); private: Ui_WdgDlgInternalColorSelector *m_ui; struct Private; //The private struct const QScopedPointer m_d; //the private pointer }; #endif // KISDLGINTERNALCOLORSELECTOR_H diff --git a/libs/widgets/KisGradientSliderWidget.cpp b/libs/widgets/KisGradientSliderWidget.cpp index 385a47b91d..a39b2e4c98 100644 --- a/libs/widgets/KisGradientSliderWidget.cpp +++ b/libs/widgets/KisGradientSliderWidget.cpp @@ -1,225 +1,225 @@ /* * Copyright (c) 2004 Cyrille Berger * 2004 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisGradientSliderWidget.h" #include #include #include #include #include #include #include #include #include #include #include #define MARGIN 5 #define HANDLE_SIZE 10 KisGradientSliderWidget::KisGradientSliderWidget(QWidget *parent, const char* name, Qt::WindowFlags f) : QWidget(parent, f), m_currentSegment(0), m_selectedSegment(0), m_drag(0) { setObjectName(name); setMinimumHeight(30); m_segmentMenu = new QMenu(); m_segmentMenu->addAction(i18n("Split Segment"), this, SLOT(slotSplitSegment())); m_segmentMenu->addAction(i18n("Duplicate Segment"), this, SLOT(slotDuplicateSegment())); m_segmentMenu->addAction(i18n("Mirror Segment"), this, SLOT(slotMirrorSegment())); m_removeSegmentAction = new QAction(i18n("Remove Segment"), this); connect(m_removeSegmentAction, SIGNAL(triggered()), this, SLOT(slotRemoveSegment())); m_segmentMenu->addAction(m_removeSegmentAction); } -void KisGradientSliderWidget::setGradientResource(KoSegmentGradient* agr) +void KisGradientSliderWidget::setGradientResource(KoSegmentGradientSP agr) { m_autogradientResource = agr; m_selectedSegment = m_autogradientResource->segmentAt(0.0); emit sigSelectedSegment(m_selectedSegment); } void KisGradientSliderWidget::paintEvent(QPaintEvent* pe) { QWidget::paintEvent(pe); QPainter painter(this); painter.fillRect(rect(), palette().background()); painter.setPen(Qt::black); painter.drawRect(MARGIN, MARGIN, width() - 2 * MARGIN, height() - 2 * MARGIN - HANDLE_SIZE); if (m_autogradientResource) { QImage image = m_autogradientResource->generatePreview(width() - 2 * MARGIN - 2, height() - 2 * MARGIN - HANDLE_SIZE - 2); QPixmap pixmap(image.width(), image.height()); if (!image.isNull()) { painter.drawImage(MARGIN + 1, MARGIN + 1, image); } painter.fillRect(MARGIN + 1, height() - MARGIN - HANDLE_SIZE, width() - 2 * MARGIN, HANDLE_SIZE, QBrush(Qt::white)); if (m_selectedSegment) { QRect selection(qRound(m_selectedSegment->startOffset()*(double)(width() - 2 * MARGIN - 2)) + 6, height() - HANDLE_SIZE - MARGIN, qRound((m_selectedSegment->endOffset() - m_selectedSegment->startOffset())*(double)(width() - 12)), HANDLE_SIZE); painter.fillRect(selection, QBrush(palette().highlight())); } QPolygon triangle(3); QList handlePositions = m_autogradientResource->getHandlePositions(); int position; painter.setBrush(QBrush(Qt::black)); for (int i = 0; i < handlePositions.count(); i++) { position = qRound(handlePositions[i] * (double)(width() - 12)) + 6; triangle[0] = QPoint(position, height() - HANDLE_SIZE - MARGIN); triangle[1] = QPoint(position + (HANDLE_SIZE / 2 - 1), height() - MARGIN); triangle[2] = QPoint(position - (HANDLE_SIZE / 2 - 1), height() - MARGIN); painter.drawPolygon(triangle); } painter.setBrush(QBrush(Qt::white)); QList middleHandlePositions = m_autogradientResource->getMiddleHandlePositions(); for (int i = 0; i < middleHandlePositions.count(); i++) { position = qRound(middleHandlePositions[i] * (double)(width() - 12)) + 6; triangle[0] = QPoint(position, height() - HANDLE_SIZE - MARGIN); triangle[1] = QPoint(position + (HANDLE_SIZE / 2 - 2), height() - MARGIN); triangle[2] = QPoint(position - (HANDLE_SIZE / 2 - 2), height() - MARGIN); painter.drawPolygon(triangle); } } } void KisGradientSliderWidget::mousePressEvent(QMouseEvent * e) { if ((e->y() < MARGIN || e->y() > height() - MARGIN) || (e->x() < MARGIN || e->x() > width() - MARGIN) || e-> button() != Qt::LeftButton) { QWidget::mousePressEvent(e); return; } double t = (double)(e->x() - MARGIN) / (double)(width() - 2 * MARGIN); KoGradientSegment* segment = 0; segment = m_autogradientResource->segmentAt(t); if (segment != 0) { m_currentSegment = segment; QRect leftHandle(qRound(m_currentSegment->startOffset() *(double)(width() - 2*MARGIN - 2) + MARGIN - (HANDLE_SIZE / 2 - 1)), height() - HANDLE_SIZE, HANDLE_SIZE - 1, HANDLE_SIZE); QRect middleHandle(qRound(m_currentSegment->middleOffset() *(double)(width() - 2*MARGIN - 2) + MARGIN - (HANDLE_SIZE / 2 - 2)), height() - HANDLE_SIZE - MARGIN, HANDLE_SIZE - 1, HANDLE_SIZE); QRect rightHandle(qRound(m_currentSegment->endOffset() *(double)(width() - 2*MARGIN - 2) + MARGIN - (HANDLE_SIZE / 2 - 1)), height() - HANDLE_SIZE, HANDLE_SIZE - 1, HANDLE_SIZE); // Change the activation order of the handles to avoid deadlocks if (t > 0.5) { if (leftHandle.contains(e->pos())) m_drag = LEFT_DRAG; else if (middleHandle.contains(e->pos())) m_drag = MIDDLE_DRAG; else if (rightHandle.contains(e->pos())) m_drag = RIGHT_DRAG; } else { if (rightHandle.contains(e->pos())) m_drag = RIGHT_DRAG; else if (middleHandle.contains(e->pos())) m_drag = MIDDLE_DRAG; else if (leftHandle.contains(e->pos())) m_drag = LEFT_DRAG; } if (m_drag == NO_DRAG) { m_selectedSegment = m_currentSegment; emit sigSelectedSegment(m_selectedSegment); } } repaint(); } void KisGradientSliderWidget::mouseReleaseEvent(QMouseEvent * e) { Q_UNUSED(e); m_drag = NO_DRAG; } void KisGradientSliderWidget::mouseMoveEvent(QMouseEvent * e) { if ((e->y() < MARGIN || e->y() > height() - MARGIN) || (e->x() < MARGIN || e->x() > width() - MARGIN)) { QWidget::mouseMoveEvent(e); return; } double t = (double)(e->x() - MARGIN) / (double)(width() - 2 * MARGIN); switch (m_drag) { case RIGHT_DRAG: m_autogradientResource->moveSegmentEndOffset(m_currentSegment, t); break; case LEFT_DRAG: m_autogradientResource->moveSegmentStartOffset(m_currentSegment, t); break; case MIDDLE_DRAG: m_autogradientResource->moveSegmentMiddleOffset(m_currentSegment, t); break; } if (m_drag != NO_DRAG) emit sigChangedSegment(m_currentSegment); repaint(); } void KisGradientSliderWidget::contextMenuEvent(QContextMenuEvent * e) { m_removeSegmentAction->setEnabled(m_autogradientResource->removeSegmentPossible()); m_segmentMenu->popup(e->globalPos()); } void KisGradientSliderWidget::slotSplitSegment() { m_autogradientResource->splitSegment(m_selectedSegment); emit sigSelectedSegment(m_selectedSegment); repaint(); } void KisGradientSliderWidget::slotDuplicateSegment() { m_autogradientResource->duplicateSegment(m_selectedSegment); emit sigSelectedSegment(m_selectedSegment); repaint(); } void KisGradientSliderWidget::slotMirrorSegment() { m_autogradientResource->mirrorSegment(m_selectedSegment); emit sigSelectedSegment(m_selectedSegment); repaint(); } void KisGradientSliderWidget::slotRemoveSegment() { m_selectedSegment = m_autogradientResource->removeSegment(m_selectedSegment); emit sigSelectedSegment(m_selectedSegment); repaint(); } diff --git a/libs/widgets/KisGradientSliderWidget.h b/libs/widgets/KisGradientSliderWidget.h index d48866ead0..6951aa9b99 100644 --- a/libs/widgets/KisGradientSliderWidget.h +++ b/libs/widgets/KisGradientSliderWidget.h @@ -1,91 +1,91 @@ /* * Copyright (c) 2004 Cyrille Berger * 2004 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KIS_GRADIENT_SLIDER_WIDGET_H_ #define _KIS_GRADIENT_SLIDER_WIDGET_H_ #include #include #include +#include + class QAction; class QMenu; + class KoGradientSegment; -class KoSegmentGradient; #include "kritawidgets_export.h" /** * @brief The KisGradientSliderWidget class makes it possible to edit gradients. */ class KRITAWIDGETS_EXPORT KisGradientSliderWidget : public QWidget { Q_OBJECT public: KisGradientSliderWidget(QWidget *parent = 0, const char* name = 0, Qt::WindowFlags f = 0); public: void paintEvent(QPaintEvent *) override; - void setGradientResource(KoSegmentGradient* agr); - KoGradientSegment* selectedSegment() { - return m_selectedSegment; - } + void setGradientResource(KoSegmentGradientSP agr); + KoGradientSegment *selectedSegment() { return m_selectedSegment; } Q_SIGNALS: void sigSelectedSegment(KoGradientSegment*); void sigChangedSegment(KoGradientSegment*); protected: void mousePressEvent(QMouseEvent * e) override; void mouseReleaseEvent(QMouseEvent * e) override; void mouseMoveEvent(QMouseEvent * e) override; void contextMenuEvent(QContextMenuEvent * e) override; private Q_SLOTS: void slotSplitSegment(); void slotDuplicateSegment(); void slotMirrorSegment(); void slotRemoveSegment(); private: enum { NO_DRAG, LEFT_DRAG, RIGHT_DRAG, MIDDLE_DRAG }; enum { SPLIT_SEGMENT, DUPLICATE_SEGMENT, MIRROR_SEGMENT, REMOVE_SEGMENT }; - KoSegmentGradient* m_autogradientResource; + KoSegmentGradientSP m_autogradientResource; KoGradientSegment* m_currentSegment; KoGradientSegment* m_selectedSegment; QMenu* m_segmentMenu; int m_drag; QAction *m_removeSegmentAction; }; #endif diff --git a/libs/widgets/KisPaletteComboBox.cpp b/libs/widgets/KisPaletteComboBox.cpp index 494dad732e..df15a01fde 100644 --- a/libs/widgets/KisPaletteComboBox.cpp +++ b/libs/widgets/KisPaletteComboBox.cpp @@ -1,162 +1,162 @@ /* * Copyright (c) 2018 Michael Zhou * * 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. */ // Qt #include #include #include #include // STL #include #include "kis_palette_view.h" #include "KisPaletteComboBox.h" KisPaletteComboBox::KisPaletteComboBox(QWidget *parent) : SqueezedComboBox(parent) , m_model(Q_NULLPTR) { setEditable(true); setInsertPolicy(NoInsert); completer()->setCompletionMode(QCompleter::PopupCompletion); completer()->setCaseSensitivity(Qt::CaseInsensitive); completer()->setFilterMode(Qt::MatchContains); connect(this, SIGNAL(currentIndexChanged(int)), SLOT(slotIndexUpdated(int))); } KisPaletteComboBox::~KisPaletteComboBox() { } void KisPaletteComboBox::setPaletteModel(const KisPaletteModel *paletteModel) { if (!m_model.isNull()) { m_model->disconnect(this); } m_model = paletteModel; if (m_model.isNull()) { return; } slotPaletteChanged(); connect(m_model, SIGNAL(sigPaletteChanged()), SLOT(slotPaletteChanged())); connect(m_model, SIGNAL(sigPaletteModified()), SLOT(slotPaletteChanged())); } void KisPaletteComboBox::setCompanionView(KisPaletteView *view) { if (!m_view.isNull()) { m_view->disconnect(this); disconnect(m_view.data()); } m_view = view; setPaletteModel(view->paletteModel()); connect(view, SIGNAL(sigIndexSelected(QModelIndex)), SLOT(slotSwatchSelected(QModelIndex))); connect(this, SIGNAL(sigColorSelected(KoColor)), view, SLOT(slotFGColorChanged(KoColor))); } void KisPaletteComboBox::slotPaletteChanged() { clear(); m_groupMapMap.clear(); m_idxSwatchMap.clear(); - if (QPointer(m_model->colorSet()).isNull()) { return; } + if (QSharedPointer(m_model->colorSet()).isNull()) { return; } for (const QString &groupName : m_model->colorSet()->getGroupNames()) { QVector infoList; PosIdxMapType posIdxMap; const KisSwatchGroup *group = m_model->colorSet()->getGroup(groupName); for (const SwatchInfoType &info : group->infoList()) { infoList.append(info); } std::sort(infoList.begin(), infoList.end(), swatchInfoLess); for (const SwatchInfoType &info : infoList) { const KisSwatch &swatch = info.swatch; QString name = swatch.name(); if (!swatch.id().isEmpty()){ name = swatch.id() + " - " + swatch.name(); } addSqueezedItem(QIcon(createColorSquare(swatch)), name); posIdxMap[SwatchPosType(info.column, info.row)] = count() - 1; m_idxSwatchMap.push_back(swatch); } m_groupMapMap[group->name()] = posIdxMap; } if (m_view.isNull()) { setCurrentIndex(0); } QModelIndex idx = m_view->currentIndex(); if (!idx.isValid()) { return; } if (qvariant_cast(idx.data(KisPaletteModel::IsGroupNameRole))) { return; } if (!qvariant_cast(idx.data(KisPaletteModel::CheckSlotRole))) { return; } blockSignals(true); // this is a passive selection; this shouldn't make others change slotSwatchSelected(idx); blockSignals(false); } bool KisPaletteComboBox::swatchInfoLess(const SwatchInfoType &first, const SwatchInfoType &second) { return first.swatch.name() < second.swatch.name(); } QPixmap KisPaletteComboBox::createColorSquare(const KisSwatch &swatch) const { QPixmap colorSquare(32, 32); if (swatch.spotColor()) { QImage img = QImage(32, 32, QImage::Format_ARGB32); QPainter circlePainter; img.fill(Qt::transparent); circlePainter.begin(&img); QBrush brush = QBrush(Qt::SolidPattern); brush.setColor(swatch.color().toQColor()); circlePainter.setBrush(brush); QPen pen = circlePainter.pen(); pen.setColor(Qt::transparent); pen.setWidth(0); circlePainter.setPen(pen); circlePainter.drawEllipse(0, 0, 32, 32); circlePainter.end(); colorSquare = QPixmap::fromImage(img); } else { colorSquare.fill(swatch.color().toQColor()); } return colorSquare; } void KisPaletteComboBox::slotSwatchSelected(const QModelIndex &index) { if (!qvariant_cast(index.data(KisPaletteModel::CheckSlotRole))) { return; } if (qvariant_cast(index.data(KisPaletteModel::IsGroupNameRole))) { return; } QString gName = qvariant_cast(index.data(KisPaletteModel::GroupNameRole)); int rowInGroup = qvariant_cast(index.data(KisPaletteModel::RowInGroupRole)); setCurrentIndex(m_groupMapMap[gName][SwatchPosType(index.column(), rowInGroup)]); } void KisPaletteComboBox::slotIndexUpdated(int idx) { if (idx >= 0 && idx < m_idxSwatchMap.size()) { emit sigColorSelected(m_idxSwatchMap[idx].color()); } } diff --git a/libs/widgets/KisPaletteListWidget.cpp b/libs/widgets/KisPaletteListWidget.cpp index 8da83d60a6..088b4511a3 100644 --- a/libs/widgets/KisPaletteListWidget.cpp +++ b/libs/widgets/KisPaletteListWidget.cpp @@ -1,196 +1,196 @@ /* * Copyright (c) 2013 Sven Langkamp * Copyright (c) 2018 Michael Zhou * * 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 #include #include #include #include #include #include #include #include #include #include #include #include "KisPaletteListWidget.h" #include "KisPaletteListWidget_p.h" KisPaletteListWidget::KisPaletteListWidget(QWidget *parent) : QWidget(parent) , m_ui(new Ui_WdgPaletteListWidget) , m_d(new KisPaletteListWidgetPrivate(this)) { m_d->allowModification = false; m_d->actAdd.reset(new QAction(KisIconUtils::loadIcon("list-add"), i18n("Add a new palette"))); m_d->actRemove.reset(new QAction(KisIconUtils::loadIcon("list-remove"), i18n("Remove current palette"))); m_d->actImport.reset(new QAction(KisIconUtils::loadIcon("document-import"), i18n("Import a new palette from file"))); m_d->actExport.reset(new QAction(KisIconUtils::loadIcon("document-export"), i18n("Export current palette to file"))); m_d->model->setColumnCount(1); m_ui->setupUi(this); m_ui->bnAdd->setDefaultAction(m_d->actAdd.data()); m_ui->bnRemove->setDefaultAction(m_d->actRemove.data()); m_ui->bnImport->setDefaultAction(m_d->actImport.data()); m_ui->bnExport->setDefaultAction(m_d->actExport.data()); m_ui->bnAdd->setEnabled(false); m_ui->bnRemove->setEnabled(false); m_ui->bnImport->setEnabled(false); m_ui->bnExport->setEnabled(false); connect(m_d->actAdd.data(), SIGNAL(triggered()), SLOT(slotAdd())); connect(m_d->actRemove.data(), SIGNAL(triggered()), SLOT(slotRemove())); connect(m_d->actImport.data(), SIGNAL(triggered()), SLOT(slotImport())); connect(m_d->actExport.data(), SIGNAL(triggered()), SLOT(slotExport())); m_d->itemChooser->setItemDelegate(m_d->delegate.data()); m_d->itemChooser->setRowHeight(40); m_d->itemChooser->setColumnCount(1); m_d->itemChooser->showButtons(false); m_d->itemChooser->showTaggingBar(true); m_ui->viewPalette->setLayout(new QHBoxLayout(m_ui->viewPalette)); m_ui->viewPalette->layout()->addWidget(m_d->itemChooser.data()); - connect(m_d->itemChooser.data(), SIGNAL(resourceSelected(KoResource*)), SLOT(slotPaletteResourceSelected(KoResource*))); + connect(m_d->itemChooser.data(), SIGNAL(resourceSelected(KoResourceSP )), SLOT(slotPaletteResourceSelected(KoResourceSP ))); } KisPaletteListWidget::~KisPaletteListWidget() { } -void KisPaletteListWidget::slotPaletteResourceSelected(KoResource *r) +void KisPaletteListWidget::slotPaletteResourceSelected(KoResourceSP r) { - KoColorSet *g = static_cast(r); + KoColorSetSP g = r.staticCast(); emit sigPaletteSelected(g); if (!m_d->allowModification) { return; } if (g->isEditable()) { m_ui->bnRemove->setEnabled(true); } else { m_ui->bnRemove->setEnabled(false); } } void KisPaletteListWidget::slotAdd() { if (!m_d->allowModification) { return; } emit sigAddPalette(); m_d->itemChooser->setCurrentItem(m_d->rAdapter->resources().size() - 1, 0); } void KisPaletteListWidget::slotRemove() { if (!m_d->allowModification) { return; } if (m_d->itemChooser->currentResource()) { - KoColorSet *cs = static_cast(m_d->itemChooser->currentResource()); + KoColorSetSP cs = m_d->itemChooser->currentResource().staticCast(); emit sigRemovePalette(cs); } m_d->itemChooser->setCurrentItem(0, 0); } void KisPaletteListWidget::slotImport() { if (!m_d->allowModification) { return; } emit sigImportPalette(); m_d->itemChooser->setCurrentItem(m_d->rAdapter->resources().size()-1, 0); } void KisPaletteListWidget::slotExport() { if (!m_d->allowModification) { return; } - emit sigExportPalette(static_cast(m_d->itemChooser->currentResource())); + emit sigExportPalette(m_d->itemChooser->currentResource().staticCast()); } void KisPaletteListWidget::setAllowModification(bool allowModification) { m_d->allowModification = allowModification; m_ui->bnAdd->setEnabled(allowModification); m_ui->bnImport->setEnabled(allowModification); m_ui->bnExport->setEnabled(allowModification); - KoColorSet *cs = static_cast(m_d->itemChooser->currentResource()); + KoColorSetSP cs = m_d->itemChooser->currentResource().staticCast(); m_ui->bnRemove->setEnabled(allowModification && cs && cs->isEditable()); } /************************* KisPaletteListWidgetPrivate **********************/ KisPaletteListWidgetPrivate::KisPaletteListWidgetPrivate(KisPaletteListWidget *a_c) : c(a_c) , rAdapter(new KoResourceServerAdapter(KoResourceServerProvider::instance()->paletteServer())) , itemChooser(new KoResourceItemChooser(rAdapter, a_c)) , model(new Model(rAdapter, a_c)) , delegate(new Delegate(a_c)) { } KisPaletteListWidgetPrivate::~KisPaletteListWidgetPrivate() { } /******************* KisPaletteListWidgetPrivate::Delegate ******************/ KisPaletteListWidgetPrivate::Delegate::Delegate(QObject *parent) : QAbstractItemDelegate(parent) { } KisPaletteListWidgetPrivate::Delegate::~Delegate() { } void KisPaletteListWidgetPrivate::Delegate::paint(QPainter * painter, - const QStyleOptionViewItem & option, - const QModelIndex & index) const + const QStyleOptionViewItem & option, + const QModelIndex & index) const { painter->save(); if (!index.isValid()) return; - KoResource* resource = static_cast(index.internalPointer()); - KoColorSet* colorSet = static_cast(resource); + KoResourceSP resource = KoResourceSP(static_cast(index.internalPointer())); + KoColorSetSP colorSet = resource.staticCast(); QRect previewRect(option.rect.x() + 2, option.rect.y() + 2, option.rect.height() - 4, option.rect.height() - 4); painter->drawImage(previewRect, colorSet->image()); if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, option.palette.highlight()); painter->drawImage(previewRect, colorSet->image()); painter->setPen(option.palette.highlightedText().color()); } else { painter->setBrush(option.palette.text().color()); } QString drawnText = colorSet->name() + (colorSet->isEditable() ? "" : i18n(" [READONLY]")); painter->drawText(option.rect.x() + previewRect.width() + 10, option.rect.y() + painter->fontMetrics().ascent() + 5, drawnText); painter->restore(); } inline QSize KisPaletteListWidgetPrivate::Delegate::sizeHint(const QStyleOptionViewItem & option, - const QModelIndex &) const + const QModelIndex &) const { return option.decorationSize; } diff --git a/libs/widgets/KisPaletteListWidget.h b/libs/widgets/KisPaletteListWidget.h index 482caf3b88..033a6fbbfa 100644 --- a/libs/widgets/KisPaletteListWidget.h +++ b/libs/widgets/KisPaletteListWidget.h @@ -1,68 +1,70 @@ /* * Copyright (c) 2013 Sven Langkamp * Copyright (c) 2018 Michael Zhou * * 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 KISPALETTELISTWIDGET_H #define KISPALETTELISTWIDGET_H #include #include #include #include "kritawidgets_export.h" +#include + class KoResource; -class KoColorSet; + class KisPaletteListWidgetPrivate; class KRITAWIDGETS_EXPORT KisPaletteListWidget : public QWidget { Q_OBJECT public: explicit KisPaletteListWidget(QWidget *parent = nullptr); virtual ~KisPaletteListWidget(); public: void setAllowModification(bool allowModification); Q_SIGNALS: - void sigPaletteSelected(KoColorSet*); + void sigPaletteSelected(KoColorSetSP); void sigAddPalette(); - void sigRemovePalette(KoColorSet *); + void sigRemovePalette(KoColorSetSP); void sigImportPalette(); - void sigExportPalette(KoColorSet *); + void sigExportPalette(KoColorSetSP); public Q_SLOTS: private /* methods */: QString newPaletteFileName(); private Q_SLOTS: - void slotPaletteResourceSelected(KoResource *); + void slotPaletteResourceSelected(KoResourceSP); void slotAdd(); void slotRemove(); void slotImport(); void slotExport(); private: QScopedPointer m_ui; QScopedPointer m_d; }; #endif // KISPALETTELISTWIDGET_H diff --git a/libs/widgets/KisPaletteModel.cpp b/libs/widgets/KisPaletteModel.cpp index f106d10d39..f759e28f60 100644 --- a/libs/widgets/KisPaletteModel.cpp +++ b/libs/widgets/KisPaletteModel.cpp @@ -1,508 +1,508 @@ /* * Copyright (c) 2013 Sven Langkamp * Copyright (c) 2018 Michael Zhou * * 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 "KisPaletteModel.h" #include #include #include #include #include #include #include #include #include KisPaletteModel::KisPaletteModel(QObject* parent) : QAbstractTableModel(parent) , m_colorSet(Q_NULLPTR) , m_displayRenderer(KoDumbColorDisplayRenderer::instance()) { connect(this, SIGNAL(sigPaletteModified()), SLOT(slotPaletteModified())); } KisPaletteModel::~KisPaletteModel() { } QVariant KisPaletteModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { return QVariant(); } bool groupNameRow = m_rowGroupNameMap.contains(index.row()); if (role == IsGroupNameRole) { return groupNameRow; } if (groupNameRow) { return dataForGroupNameRow(index, role); } else { return dataForSwatch(index, role); } } int KisPaletteModel::rowCount(const QModelIndex& /*parent*/) const { if (!m_colorSet) return 0; return m_colorSet->rowCount() // count of color rows + m_rowGroupNameMap.size() // rows for names - 1; // global doesn't have a name } int KisPaletteModel::columnCount(const QModelIndex& /*parent*/) const { if (m_colorSet && m_colorSet->columnCount() > 0) { return m_colorSet->columnCount(); } if (!m_colorSet) { return 0; } return 16; } Qt::ItemFlags KisPaletteModel::flags(const QModelIndex& index) const { if (index.isValid()) { return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } return Qt::ItemIsDropEnabled; } QModelIndex KisPaletteModel::index(int row, int column, const QModelIndex& parent) const { Q_UNUSED(parent); Q_ASSERT(m_colorSet); int groupNameRow = groupNameRowForRow(row); KisSwatchGroup *group = m_colorSet->getGroup(m_rowGroupNameMap[groupNameRow]); Q_ASSERT(group); return createIndex(row, column, group); } void KisPaletteModel::resetGroupNameRows() { m_rowGroupNameMap.clear(); int row = -1; for (const QString &groupName : m_colorSet->getGroupNames()) { m_rowGroupNameMap[row] = groupName; row += m_colorSet->getGroup(groupName)->rowCount(); row += 1; // row for group name } } -void KisPaletteModel::setPalette(KoColorSet* palette) +void KisPaletteModel::setPalette(KoColorSetSP palette) { beginResetModel(); m_colorSet = palette; if (palette) { resetGroupNameRows(); } endResetModel(); emit sigPaletteChanged(); } -KoColorSet* KisPaletteModel::colorSet() const +KoColorSetSP KisPaletteModel::colorSet() const { return m_colorSet; } int KisPaletteModel::rowNumberInGroup(int rowInModel) const { if (m_rowGroupNameMap.contains(rowInModel)) { return -1; } QList rowNumberList = m_rowGroupNameMap.keys(); for (auto it = rowNumberList.rbegin(); it != rowNumberList.rend(); it++) { if (*it < rowInModel) { return rowInModel - *it - 1; } } return rowInModel; } int KisPaletteModel::groupNameRowForName(const QString &groupName) { for (auto it = m_rowGroupNameMap.begin(); it != m_rowGroupNameMap.end(); it++) { if (it.value() == groupName) { return it.key(); } } return -1; } bool KisPaletteModel::addEntry(const KisSwatch &entry, const QString &groupName) { beginInsertRows(QModelIndex(), rowCount(), rowCount() + 1); m_colorSet->add(entry, groupName); endInsertRows(); if (m_colorSet->isGlobal()) { m_colorSet->save(); } emit sigPaletteModified(); return true; } bool KisPaletteModel::removeEntry(const QModelIndex &index, bool keepColors) { if (!qvariant_cast(data(index, IsGroupNameRole))) { static_cast(index.internalPointer())->removeEntry(index.column(), rowNumberInGroup(index.row())); emit dataChanged(index, index); } else { int groupNameRow = groupNameRowForRow(index.row()); QString groupName = m_rowGroupNameMap[groupNameRow]; removeGroup(groupName, keepColors); } emit sigPaletteModified(); return true; } void KisPaletteModel::removeGroup(const QString &groupName, bool keepColors) { int removeStart = groupNameRowForName(groupName); int removedRowCount = m_colorSet->getGroup(groupName)->rowCount(); int insertStart = m_colorSet->getGlobalGroup()->rowCount(); beginRemoveRows(QModelIndex(), removeStart, removeStart + removedRowCount); m_colorSet->removeGroup(groupName, keepColors); resetGroupNameRows(); endRemoveRows(); beginInsertRows(QModelIndex(), insertStart, m_colorSet->getGlobalGroup()->rowCount()); endInsertRows(); emit sigPaletteModified(); } bool KisPaletteModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { Q_UNUSED(row); Q_UNUSED(column); if (!data->hasFormat("krita/x-colorsetentry") && !data->hasFormat("krita/x-colorsetgroup")) { return false; } if (action == Qt::IgnoreAction) { return false; } QModelIndex finalIndex = parent; if (!finalIndex.isValid()) { return false; } if (data->hasFormat("krita/x-colorsetgroup")) { // dragging group not supported for now QByteArray encodedData = data->data("krita/x-colorsetgroup"); QDataStream stream(&encodedData, QIODevice::ReadOnly); while (!stream.atEnd()) { QString groupNameDroppedOn = qvariant_cast(finalIndex.data(GroupNameRole)); if (groupNameDroppedOn == KoColorSet::GLOBAL_GROUP_NAME) { return false; } QString groupNameDragged; stream >> groupNameDragged; KisSwatchGroup *groupDragged = m_colorSet->getGroup(groupNameDragged); int start = groupNameRowForName(groupNameDragged); int end = start + groupDragged->rowCount(); if (!beginMoveRows(QModelIndex(), start, end, QModelIndex(), groupNameRowForName(groupNameDroppedOn))) { return false; } m_colorSet->moveGroup(groupNameDragged, groupNameDroppedOn); resetGroupNameRows(); endMoveRows(); emit sigPaletteModified(); if (m_colorSet->isGlobal()) { m_colorSet->save(); } } return true; } if (qvariant_cast(finalIndex.data(KisPaletteModel::IsGroupNameRole))) { return true; } QByteArray encodedData = data->data("krita/x-colorsetentry"); QDataStream stream(&encodedData, QIODevice::ReadOnly); while (!stream.atEnd()) { KisSwatch entry; QString name, id; bool spotColor; QString oldGroupName; int oriRow; int oriColumn; QString colorXml; stream >> name >> id >> spotColor >> oriRow >> oriColumn >> oldGroupName >> colorXml; entry.setName(name); entry.setId(id); entry.setSpotColor(spotColor); QDomDocument doc; doc.setContent(colorXml); QDomElement e = doc.documentElement(); QDomElement c = e.firstChildElement(); if (!c.isNull()) { QString colorDepthId = c.attribute("bitdepth", Integer8BitsColorDepthID.id()); entry.setColor(KoColor::fromXML(c, colorDepthId)); } if (action == Qt::MoveAction){ KisSwatchGroup *g = m_colorSet->getGroup(oldGroupName); if (g) { if (qvariant_cast(finalIndex.data(KisPaletteModel::CheckSlotRole))) { g->setEntry(getEntry(finalIndex), oriColumn, oriRow); } else { g->removeEntry(oriColumn, oriRow); } } setEntry(entry, finalIndex); emit sigPaletteModified(); if (m_colorSet->isGlobal()) { m_colorSet->save(); } } } return true; } QMimeData *KisPaletteModel::mimeData(const QModelIndexList &indexes) const { QMimeData *mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); QModelIndex index = indexes.last(); if (index.isValid() && qvariant_cast(index.data(CheckSlotRole))) { QString mimeTypeName = "krita/x-colorsetentry"; if (qvariant_cast(index.data(IsGroupNameRole))==false) { KisSwatch entry = getEntry(index); QDomDocument doc; QDomElement root = doc.createElement("Color"); root.setAttribute("bitdepth", entry.color().colorSpace()->colorDepthId().id()); doc.appendChild(root); entry.color().toXML(doc, root); stream << entry.name() << entry.id() << entry.spotColor() << rowNumberInGroup(index.row()) << index.column() << qvariant_cast(index.data(GroupNameRole)) << doc.toString(); } else { mimeTypeName = "krita/x-colorsetgroup"; QString groupName = qvariant_cast(index.data(GroupNameRole)); stream << groupName; } mimeData->setData(mimeTypeName, encodedData); } return mimeData; } QStringList KisPaletteModel::mimeTypes() const { return QStringList() << "krita/x-colorsetentry" << "krita/x-colorsetgroup"; } Qt::DropActions KisPaletteModel::supportedDropActions() const { return Qt::MoveAction; } void KisPaletteModel::setEntry(const KisSwatch &entry, const QModelIndex &index) { KisSwatchGroup *group = static_cast(index.internalPointer()); Q_ASSERT(group); group->setEntry(entry, index.column(), rowNumberInGroup(index.row())); emit sigPaletteModified(); emit dataChanged(index, index); if (m_colorSet->isGlobal()) { m_colorSet->save(); } } bool KisPaletteModel::renameGroup(const QString &groupName, const QString &newName) { beginResetModel(); bool success = m_colorSet->changeGroupName(groupName, newName); for (auto it = m_rowGroupNameMap.begin(); it != m_rowGroupNameMap.end(); it++) { if (it.value() == groupName) { m_rowGroupNameMap[it.key()] = newName; break; } } endResetModel(); emit sigPaletteModified(); return success; } void KisPaletteModel::addGroup(const KisSwatchGroup &group) { beginInsertRows(QModelIndex(), rowCount(), rowCount() + group.rowCount()); m_colorSet->addGroup(group.name()); *m_colorSet->getGroup(group.name()) = group; endInsertColumns(); emit sigPaletteModified(); } void KisPaletteModel::setRowNumber(const QString &groupName, int rowCount) { beginResetModel(); KisSwatchGroup *g = m_colorSet->getGroup(groupName); if (g) { g->setRowCount(rowCount); } endResetModel(); } void KisPaletteModel::clear() { beginResetModel(); m_colorSet->clear(); endResetModel(); } QVariant KisPaletteModel::dataForGroupNameRow(const QModelIndex &idx, int role) const { KisSwatchGroup *group = static_cast(idx.internalPointer()); Q_ASSERT(group); QString groupName = group->name(); switch (role) { case Qt::ToolTipRole: case Qt::DisplayRole: { return groupName; } case GroupNameRole: { return groupName; } case CheckSlotRole: { return true; } case RowInGroupRole: { return -1; } default: { return QVariant(); } } } QVariant KisPaletteModel::dataForSwatch(const QModelIndex &idx, int role) const { KisSwatchGroup *group = static_cast(idx.internalPointer()); Q_ASSERT(group); int rowInGroup = rowNumberInGroup(idx.row()); bool entryPresent = group->checkEntry(idx.column(), rowInGroup); KisSwatch entry; if (entryPresent) { entry = group->getEntry(idx.column(), rowInGroup); } switch (role) { case Qt::ToolTipRole: case Qt::DisplayRole: { return entryPresent ? entry.name() : i18n("Empty slot"); } case Qt::BackgroundRole: { QColor color(0, 0, 0, 0); if (entryPresent) { color = m_displayRenderer->toQColor(entry.color()); } return QBrush(color); } case GroupNameRole: { return group->name(); } case CheckSlotRole: { return entryPresent; } case RowInGroupRole: { return rowInGroup; } default: { return QVariant(); } } } void KisPaletteModel::setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer) { if (displayRenderer) { if (m_displayRenderer) { disconnect(m_displayRenderer, 0, this, 0); } m_displayRenderer = displayRenderer; connect(m_displayRenderer, SIGNAL(displayConfigurationChanged()), SLOT(slotDisplayConfigurationChanged())); } else { m_displayRenderer = KoDumbColorDisplayRenderer::instance(); } } void KisPaletteModel::slotDisplayConfigurationChanged() { beginResetModel(); endResetModel(); } void KisPaletteModel::slotPaletteModified() { m_colorSet->setPaletteType(KoColorSet::KPL); } QModelIndex KisPaletteModel::indexForClosest(const KoColor &compare) { KisSwatchGroup::SwatchInfo info = colorSet()->getClosestColorInfo(compare); return createIndex(indexRowForInfo(info), info.column, colorSet()->getGroup(info.group)); } int KisPaletteModel::indexRowForInfo(const KisSwatchGroup::SwatchInfo &info) { for (auto it = m_rowGroupNameMap.begin(); it != m_rowGroupNameMap.end(); it++) { if (it.value() == info.group) { return it.key() + info.row + 1; } } return info.row; } KisSwatch KisPaletteModel::getEntry(const QModelIndex &index) const { KisSwatchGroup *group = static_cast(index.internalPointer()); if (!group || !group->checkEntry(index.column(), rowNumberInGroup(index.row()))) { return KisSwatch(); } return group->getEntry(index.column(), rowNumberInGroup(index.row())); } int KisPaletteModel::groupNameRowForRow(int rowInModel) const { return rowInModel - rowNumberInGroup(rowInModel) - 1; } diff --git a/libs/widgets/KisPaletteModel.h b/libs/widgets/KisPaletteModel.h index 45f465a405..ca2c71a5dd 100644 --- a/libs/widgets/KisPaletteModel.h +++ b/libs/widgets/KisPaletteModel.h @@ -1,179 +1,179 @@ /* * Copyright (c) 2013 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_PALETTEMODEL_H #define KIS_PALETTEMODEL_H #include #include #include #include #include "kritawidgets_export.h" #include #include class KoColorSet; class KisPaletteView; /** * @brief The KisPaletteModel class * This, together with KisPaletteView and KisPaletteDelegate forms a mvc way to access kocolorsets. * A display renderer is given to this model to convert KoColor to QColor when * colors are requested */ class KRITAWIDGETS_EXPORT KisPaletteModel : public QAbstractTableModel { Q_OBJECT public: explicit KisPaletteModel(QObject* parent = Q_NULLPTR); ~KisPaletteModel() override; enum AdditionalRoles { IsGroupNameRole = Qt::UserRole + 1, CheckSlotRole, GroupNameRole, RowInGroupRole }; public /* overridden methods */: // QAbstractTableModel QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; /** * @brief index * @param row * @param column * @param parent * @return the index of for the data at row, column * if the data is a color entry, the internal pointer points to the group * the entry belongs to, and the row and column are row number and column * number inside the group. * if the data is a group, the row number and group number is Q_INFINIFY, * and the internal pointer also points to the group */ QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; Qt::ItemFlags flags(const QModelIndex& index) const override; /** * @brief dropMimeData * This is an overridden function that handles dropped mimedata. * right now only colorsetentries and colorsetgroups are handled. * @return */ bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; /** * @brief mimeData * gives the mimedata for a kocolorsetentry or a kocolorsetgroup. * @param indexes * @return the mimedata for the given indices */ QMimeData *mimeData(const QModelIndexList &indexes) const override; QStringList mimeTypes() const override; Qt::DropActions supportedDropActions() const override; /** * @brief setData * setData is not used as KoColor is not a QVariant * use setEntry, addEntry and removeEntry instead */ // TODO Used QVariant::setValue and QVariant.value to implement this // bool setData(const QModelIndex &index, const QVariant &value, int role) override; Q_SIGNALS: /** * @brief sigPaletteModified * emitted when palette associated with the model is modified */ void sigPaletteModified(); /** * @brief sigPaletteChanged * emitted when the palette associated with the model is made another one */ void sigPaletteChanged(); public /* methods */: /** * @brief addEntry * proper function to handle adding entries. * @return whether successful. */ bool addEntry(const KisSwatch &entry, const QString &groupName = KoColorSet::GLOBAL_GROUP_NAME); void setEntry(const KisSwatch &entry, const QModelIndex &index); /** * @brief removeEntry * proper function to remove the colorsetentry at the given index. * The consolidates both removeentry and removegroup. * @param keepColors: This bool determines whether, when deleting a group, * the colors should be added to the default group. This is usually desirable, * so hence the default is true. * @return if successful */ bool removeEntry(const QModelIndex &index, bool keepColors=true); void removeGroup(const QString &groupName, bool keepColors); bool renameGroup(const QString &groupName, const QString &newName); void addGroup(const KisSwatchGroup &group); void setRowNumber(const QString &groupName, int rowCount); void clear(); KisSwatch getEntry(const QModelIndex &index) const; - void setPalette(KoColorSet* colorSet); - KoColorSet* colorSet() const; + void setPalette(KoColorSetSP colorSet); + KoColorSetSP colorSet() const; QModelIndex indexForClosest(const KoColor &compare); int indexRowForInfo(const KisSwatchGroup::SwatchInfo &info); public Q_SLOTS: private Q_SLOTS: void slotDisplayConfigurationChanged(); void slotPaletteModified(); private /* methods */: QVariant dataForGroupNameRow(const QModelIndex &idx, int role) const; QVariant dataForSwatch(const QModelIndex &idx, int role) const; int rowNumberInGroup(int rowInModel) const; int groupNameRowForRow(int rowInModel) const; int groupNameRowForName(const QString &groupName); void resetGroupNameRows(); /** * Installs a display renderer object for a palette that will * convert the KoColor to the displayable QColor. Default is the * dumb renderer. */ void setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer); private /* member variables */: - QPointer m_colorSet; + QSharedPointer m_colorSet; QPointer m_displayRenderer; QMap m_rowGroupNameMap; friend class KisPaletteView; }; #endif diff --git a/libs/widgets/KoColorPopupAction.cpp b/libs/widgets/KoColorPopupAction.cpp index 0d5f9e30ce..f9949caa02 100644 --- a/libs/widgets/KoColorPopupAction.cpp +++ b/libs/widgets/KoColorPopupAction.cpp @@ -1,247 +1,246 @@ /* This file is part of the KDE project * Copyright (c) 2007 C. Boemann * Copyright (C) 2007 Fredy Yanardi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoColorPopupAction.h" #include "KoColorSetWidget.h" #include "KoTriangleColorSelector.h" #include "KoColorSlider.h" #include "KoCheckerBoardPainter.h" #include "KoResourceServer.h" #include "KoResourceServerProvider.h" #include #include #include #include #include #include #include #include #include #include -#include class KoColorPopupAction::KoColorPopupActionPrivate { public: KoColorPopupActionPrivate() : colorSetWidget(0) , colorChooser(0) , opacitySlider(0) , menu(0) , checkerPainter(4) , showFilter(true) , applyMode(true) , firstTime(true) {} ~KoColorPopupActionPrivate() { delete menu; } KoColor currentColor; KoColor buddyColor; KoColorSetWidget *colorSetWidget; KoTriangleColorSelector * colorChooser; KoColorSlider * opacitySlider; QMenu *menu; KoCheckerBoardPainter checkerPainter; bool showFilter; bool applyMode; bool firstTime; }; KoColorPopupAction::KoColorPopupAction(QObject *parent) : QAction(parent), d(new KoColorPopupActionPrivate()) { d->menu = new QMenu(); QWidget *widget = new QWidget(d->menu); QWidgetAction *wdgAction = new QWidgetAction(d->menu); d->colorSetWidget = new KoColorSetWidget(widget); KoResourceServer* rServer = KoResourceServerProvider::instance()->paletteServer(); - QPointer defaultColorSet = rServer->resourceByName("Default"); + KoColorSetSP defaultColorSet = rServer->resourceByName("Default"); if (!defaultColorSet && rServer->resources().count() > 0) { defaultColorSet = rServer->resources().first(); } d->colorSetWidget->setColorSet(defaultColorSet); d->colorChooser = new KoTriangleColorSelector( widget ); // prevent mouse release on color selector from closing popup d->colorChooser->setAttribute( Qt::WA_NoMousePropagation ); d->opacitySlider = new KoColorSlider( Qt::Vertical, widget ); d->opacitySlider->setFixedWidth(25); d->opacitySlider->setRange(0, 255); d->opacitySlider->setValue(255); d->opacitySlider->setToolTip( i18n( "Opacity" ) ); QGridLayout * layout = new QGridLayout( widget ); layout->addWidget( d->colorSetWidget, 0, 0, 1, -1 ); layout->addWidget( d->colorChooser, 1, 0 ); layout->addWidget( d->opacitySlider, 1, 1 ); layout->setMargin(4); wdgAction->setDefaultWidget(widget); d->menu->addAction(wdgAction); setMenu(d->menu); new QHBoxLayout(d->menu); d->menu->layout()->addWidget(widget); d->menu->layout()->setMargin(0); connect(this, SIGNAL(triggered()), this, SLOT(emitColorChanged())); connect(d->colorSetWidget, SIGNAL(colorChanged(KoColor,bool)), this, SLOT(colorWasSelected(KoColor,bool))); connect(d->colorChooser, SIGNAL(colorChanged(QColor)), this, SLOT(colorWasEdited(QColor))); connect(d->opacitySlider, SIGNAL(valueChanged(int)), this, SLOT(opacityWasChanged(int))); } KoColorPopupAction::~KoColorPopupAction() { delete d; } void KoColorPopupAction::setCurrentColor( const KoColor &color ) { KoColor minColor( color ); d->currentColor = minColor; d->colorChooser->blockSignals(true); d->colorChooser->slotSetColor(color); d->colorChooser->blockSignals(false); KoColor maxColor( color ); minColor.setOpacity( OPACITY_TRANSPARENT_U8 ); maxColor.setOpacity( OPACITY_OPAQUE_U8 ); d->opacitySlider->blockSignals( true ); d->opacitySlider->setColors( minColor, maxColor ); d->opacitySlider->setValue( color.opacityU8() ); d->opacitySlider->blockSignals( false ); updateIcon(); } void KoColorPopupAction::setCurrentColor( const QColor &_color ) { #ifndef NDEBUG if (!_color.isValid()) { warnWidgets << "Invalid color given, defaulting to black"; } #endif const QColor color(_color.isValid() ? _color : QColor(0,0,0,255)); setCurrentColor(KoColor(color, KoColorSpaceRegistry::instance()->rgb8() )); } QColor KoColorPopupAction::currentColor() const { return d->currentColor.toQColor(); } KoColor KoColorPopupAction::currentKoColor() const { return d->currentColor; } void KoColorPopupAction::updateIcon() { QSize iconSize; QToolButton *toolButton = dynamic_cast(parentWidget()); if (toolButton) { iconSize = QSize(toolButton->iconSize()); } else { iconSize = QSize(16, 16); } // This must be a QImage, as drawing to a QPixmap outside the // UI thread will cause sporadic crashes. QImage pm; if (icon().isNull()) { d->applyMode = false; } if(d->applyMode) { pm = icon().pixmap(iconSize).toImage(); if (pm.isNull()) { pm = QImage(iconSize, QImage::Format_ARGB32_Premultiplied); pm.fill(Qt::transparent); } QPainter p(&pm); p.fillRect(0, iconSize.height() - 4, iconSize.width(), 4, d->currentColor.toQColor()); p.end(); } else { pm = QImage(iconSize, QImage::Format_ARGB32_Premultiplied); pm.fill(Qt::transparent); QPainter p(&pm); d->checkerPainter.paint(p, QRect(QPoint(),iconSize)); p.fillRect(0, 0, iconSize.width(), iconSize.height(), d->currentColor.toQColor()); p.end(); } setIcon(QIcon(QPixmap::fromImage(pm))); } void KoColorPopupAction::emitColorChanged() { emit colorChanged( d->currentColor ); } void KoColorPopupAction::colorWasSelected(const KoColor &color, bool final) { d->currentColor = color; if (final) { menu()->hide(); emitColorChanged(); } updateIcon(); } void KoColorPopupAction::colorWasEdited( const QColor &color ) { d->currentColor = KoColor( color, KoColorSpaceRegistry::instance()->rgb8() ); quint8 opacity = d->opacitySlider->value(); d->currentColor.setOpacity( opacity ); KoColor minColor = d->currentColor; minColor.setOpacity( OPACITY_TRANSPARENT_U8 ); KoColor maxColor = minColor; maxColor.setOpacity( OPACITY_OPAQUE_U8 ); d->opacitySlider->setColors( minColor, maxColor ); emitColorChanged(); updateIcon(); } void KoColorPopupAction::opacityWasChanged( int opacity ) { d->currentColor.setOpacity( quint8(opacity) ); emitColorChanged(); } diff --git a/libs/widgets/KoColorSetWidget.cpp b/libs/widgets/KoColorSetWidget.cpp index b57c56019c..7a771c6191 100644 --- a/libs/widgets/KoColorSetWidget.cpp +++ b/libs/widgets/KoColorSetWidget.cpp @@ -1,217 +1,216 @@ /* This file is part of the KDE project Copyright (c) 2007, 2012 C. Boemann Copyright (c) 2007-2008 Fredy Yanardi This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoColorSetWidget.h" #include "KoColorSetWidget_p.h" #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void KoColorSetWidget::KoColorSetWidgetPrivate::addRecent(const KoColor &color) { if(numRecents < 6) { recentPatches[numRecents] = new KoColorPatch(thePublic); recentPatches[numRecents]->setFrameShape(QFrame::StyledPanel); recentPatches[numRecents]->setDisplayRenderer(displayRenderer); recentsLayout->insertWidget(numRecents + 1, recentPatches[numRecents]); connect(recentPatches[numRecents], SIGNAL(triggered(KoColorPatch*)), thePublic, SLOT(slotPatchTriggered(KoColorPatch*))); numRecents++; } // shift colors to the right for (int i = numRecents- 1; i >0; i--) { recentPatches[i]->setColor(recentPatches[i-1]->color()); } //Finally set the recent color recentPatches[0]->setColor(color); } void KoColorSetWidget::KoColorSetWidgetPrivate::activateRecent(int i) { KoColor color = recentPatches[i]->color(); while (i >0) { recentPatches[i]->setColor(recentPatches[i-1]->color()); i--; } recentPatches[0]->setColor(color); } KoColorSetWidget::KoColorSetWidget(QWidget *parent) : QFrame(parent) , d(new KoColorSetWidgetPrivate()) { d->thePublic = this; d->numRecents = 0; d->recentsLayout = new QHBoxLayout; d->recentsLayout->setMargin(0); d->recentsLayout->addWidget(new QLabel(i18n("Recent:"))); d->recentsLayout->addStretch(1); KoColor color(KoColorSpaceRegistry::instance()->rgb8()); color.fromQColor(QColor(128,0,0)); d->addRecent(color); d->paletteView = new KisPaletteView(this); KisPaletteModel *paletteModel = new KisPaletteModel(d->paletteView); d->paletteView->setPaletteModel(paletteModel); d->paletteView->setDisplayRenderer(d->displayRenderer); d->paletteChooser = new KisPaletteListWidget(this); d->paletteChooserButton = new KisPopupButton(this); d->paletteChooserButton->setPopupWidget(d->paletteChooser); d->paletteChooserButton->setIcon(KisIconUtils::loadIcon("hi16-palette_library")); d->paletteChooserButton->setToolTip(i18n("Choose palette")); d->colorNameCmb = new KisPaletteComboBox(this); d->colorNameCmb->setCompanionView(d->paletteView); d->bottomLayout = new QHBoxLayout; d->bottomLayout->addWidget(d->paletteChooserButton); d->bottomLayout->addWidget(d->colorNameCmb); d->bottomLayout->setStretch(0, 0); // minimize chooser button d->bottomLayout->setStretch(1, 1); // maximize color name cmb d->mainLayout = new QVBoxLayout(this); d->mainLayout->setMargin(4); d->mainLayout->setSpacing(2); d->mainLayout->addLayout(d->recentsLayout); d->mainLayout->addWidget(d->paletteView); d->mainLayout->addLayout(d->bottomLayout); setLayout(d->mainLayout); connect(d->paletteChooser, SIGNAL(sigPaletteSelected(KoColorSet*)), SLOT(slotPaletteChoosen(KoColorSet*))); connect(d->paletteView, SIGNAL(sigColorSelected(KoColor)), SLOT(slotColorSelectedByPalette(KoColor))); connect(d->colorNameCmb, SIGNAL(sigColorSelected(KoColor)), SLOT(slotNameListSelection(KoColor))); d->rServer = KoResourceServerProvider::instance()->paletteServer(); - QPointer defaultColorSet = d->rServer->resourceByName("Default"); + KoColorSetSP defaultColorSet = d->rServer->resourceByName("Default"); if (!defaultColorSet && d->rServer->resources().count() > 0) { defaultColorSet = d->rServer->resources().first(); } setColorSet(defaultColorSet); } KoColorSetWidget::~KoColorSetWidget() { delete d; } -void KoColorSetWidget::setColorSet(QPointer colorSet) +void KoColorSetWidget::setColorSet(KoColorSetSP colorSet) { if (!colorSet) return; if (colorSet == d->colorSet) return; - d->paletteView->paletteModel()->setPalette(colorSet.data()); + d->paletteView->paletteModel()->setPalette(colorSet); d->colorSet = colorSet; } -KoColorSet* KoColorSetWidget::colorSet() +KoColorSetSP KoColorSetWidget::colorSet() { return d->colorSet; } void KoColorSetWidget::setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer) { if (displayRenderer) { d->displayRenderer = displayRenderer; for (int i=0; i<6; i++) { if (d->recentPatches[i]) { d->recentPatches[i]->setDisplayRenderer(displayRenderer); } } } } void KoColorSetWidget::resizeEvent(QResizeEvent *event) { emit widgetSizeChanged(event->size()); QFrame::resizeEvent(event); } void KoColorSetWidget::slotColorSelectedByPalette(const KoColor &color) { emit colorChanged(color, true); d->addRecent(color); } void KoColorSetWidget::slotPatchTriggered(KoColorPatch *patch) { emit colorChanged(patch->color(), true); int i; for (i = 0; i < d->numRecents; i++) { if(patch == d->recentPatches[i]) { d->activateRecent(i); break; } } if (i == d->numRecents) { // we didn't find it above d->addRecent(patch->color()); } } -void KoColorSetWidget::slotPaletteChoosen(KoColorSet *colorSet) +void KoColorSetWidget::slotPaletteChoosen(KoColorSetSP colorSet) { d->colorSet = colorSet; d->paletteView->paletteModel()->setPalette(colorSet); } void KoColorSetWidget::slotNameListSelection(const KoColor &color) { emit colorChanged(color, true); } //have to include this because of Q_PRIVATE_SLOT #include "moc_KoColorSetWidget.cpp" diff --git a/libs/widgets/KoColorSetWidget.h b/libs/widgets/KoColorSetWidget.h index fa920f5dad..a0174be89e 100644 --- a/libs/widgets/KoColorSetWidget.h +++ b/libs/widgets/KoColorSetWidget.h @@ -1,120 +1,121 @@ /* This file is part of the KDE project Copyright (c) 2007 C. Boemann Copyright (c) 2007 Fredy Yanardi This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOCOLORSETWIDGET_H_ #define KOCOLORSETWIDGET_H_ #include #include #include +#include + #include #include "kritawidgets_export.h" class KoColor; -class KoColorSet; class KoColorPatch; /** * @short A colormanaged widget for choosing a color from a colorset * * KoColorSetWidget is a widget for choosing a color (colormanaged via pigment). It shows a color * set plus optionally a checkbox to filter away bad matching colors. */ class KRITAWIDGETS_EXPORT KoColorSetWidget : public QFrame { Q_OBJECT public: /** * Constructor for the widget, where color is initially blackpoint of sRGB * * @param parent parent QWidget */ explicit KoColorSetWidget(QWidget *parent=0); /** * Destructor */ ~KoColorSetWidget() override; /** * Sets the color set that this widget shows. * @param colorSet pointer to the color set */ - void setColorSet(QPointer colorSet); + void setColorSet(KoColorSetSP colorSet); /** * @brief setDisplayRenderer * Set the display renderer of this object. * @param displayRenderer */ void setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer); /** * Gets the current color set * @returns current color set,, 0 if none set */ - KoColorSet* colorSet(); + KoColorSetSP colorSet(); protected: void resizeEvent(QResizeEvent *event) override; ///< reimplemented from QFrame Q_SIGNALS: /** * Emitted every time the color changes (by calling setColor() or * by user interaction. * @param color the new color * @param final if the value is final (ie not produced by the pointer moving over around) */ void colorChanged(const KoColor &color, bool final); /** * Emitted every time the size of this widget changes because of new colorset with * different number of colors is loaded. This is useful for KoColorSetAction to update * correct size of the menu showing this widget. * @param size the new size */ void widgetSizeChanged(const QSize &size); private Q_SLOTS: /** * @brief slotPatchTriggered * Triggered when a recent patch is triggered */ void slotPatchTriggered(KoColorPatch *); /** * @brief slotEntrySelected * Triggered when a color is choose from the palette view */ void slotColorSelectedByPalette(const KoColor &color); - void slotPaletteChoosen(KoColorSet *); + void slotPaletteChoosen(KoColorSetSP ); void slotNameListSelection(const KoColor &); private: class KoColorSetWidgetPrivate; KoColorSetWidgetPrivate * const d; }; #endif diff --git a/libs/widgets/KoColorSetWidget_p.h b/libs/widgets/KoColorSetWidget_p.h index 4c38123401..1195b12955 100644 --- a/libs/widgets/KoColorSetWidget_p.h +++ b/libs/widgets/KoColorSetWidget_p.h @@ -1,81 +1,80 @@ /* This file is part of the KDE project Copyright (c) 2007, 2012 C. Boemann Copyright (c) 2007-2008 Fredy Yanardi This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KoColorSetWidget_p_h #define KoColorSetWidget_p_h #include "KoColorSetWidget.h" #include #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include class KoColorPatch; class KisPaletteView; class Q_DECL_HIDDEN KoColorSetWidget::KoColorSetWidgetPrivate { public: KoColorSetWidget *thePublic; - QPointer colorSet; + KoColorSetSP colorSet; KisPaletteView *paletteView; KisPaletteListWidget *paletteChooser; KisPopupButton *paletteChooserButton; QVBoxLayout *mainLayout; QVBoxLayout *colorSetLayout; QHBoxLayout *recentsLayout; QHBoxLayout *bottomLayout; KoColorPatch *recentPatches[6]; QToolButton *addRemoveButton; KisPaletteComboBox *colorNameCmb; int numRecents; const KoColorDisplayRendererInterface *displayRenderer; KoResourceServer *rServer; void addRecent(const KoColor &); void activateRecent(int i); void addRemoveColors(); }; #endif diff --git a/libs/widgets/KoGradientEditWidget.cpp b/libs/widgets/KoGradientEditWidget.cpp index 31fcaba26e..5b74e60dbf 100644 --- a/libs/widgets/KoGradientEditWidget.cpp +++ b/libs/widgets/KoGradientEditWidget.cpp @@ -1,409 +1,407 @@ /* This file is part of the KDE project Copyright (C) 2001-2002 Beno�t Vautrin Copyright (C) 2002-2003 Rob Buis Copyright (C) 2006-2008,2011 Jan Hambrecht This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoGradientEditWidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void transferGradientPosition(const QGradient * srcGradient, QGradient * dstGradient) { // first check if gradients have the same type if (srcGradient->type() == dstGradient->type()) { switch (srcGradient->type()) { case QGradient::LinearGradient: { const QLinearGradient * src = static_cast(srcGradient); QLinearGradient * dst = static_cast(dstGradient); dst->setStart(src->start()); dst->setFinalStop(src->finalStop()); break; } case QGradient::RadialGradient: { const QRadialGradient * src = static_cast(srcGradient); QRadialGradient * dst = static_cast(dstGradient); dst->setCenter(src->center()); dst->setRadius(src->radius()); dst->setFocalPoint(src->focalPoint()); break; } case QGradient::ConicalGradient: { const QConicalGradient * src = static_cast(srcGradient); QConicalGradient * dst = static_cast(dstGradient); dst->setCenter(src->center()); dst->setAngle(src->angle()); break; } default: return; } return; } // try to preserve gradient positions as best as possible QPointF start, stop; switch (srcGradient->type()) { case QGradient::LinearGradient: { const QLinearGradient * g = static_cast(srcGradient); start = g->start(); stop = g->finalStop(); break; } case QGradient::RadialGradient: { const QRadialGradient * g = static_cast(srcGradient); start = g->center(); stop = QPointF(g->radius(), 0.0); break; } case QGradient::ConicalGradient: { const QConicalGradient * g = static_cast(srcGradient); start = g->center(); qreal radAngle = g->angle() * M_PI / 180.0; stop = QPointF(50.0 * cos(radAngle), 50.*sin(radAngle)); break; } default: start = QPointF(0.0, 0.0); stop = QPointF(50.0, 50.0); } switch (dstGradient->type()) { case QGradient::LinearGradient: { QLinearGradient * g = static_cast(dstGradient); g->setStart(start); g->setFinalStop(stop); break; } case QGradient::RadialGradient: { QRadialGradient * g = static_cast(dstGradient); QPointF diff = stop - start; qreal radius = sqrt(diff.x() * diff.x() + diff.y() * diff.y()); g->setCenter(start); g->setFocalPoint(start); g->setRadius(radius); break; } case QGradient::ConicalGradient: { QConicalGradient * g = static_cast(dstGradient); QPointF diff = stop - start; qreal angle = atan2(diff.y(), diff.x()); if (angle < 0.0) angle += 2 * M_PI; g->setCenter(start); g->setAngle(angle*180 / M_PI); break; } default: return; } } KoGradientEditWidget::KoGradientEditWidget(QWidget* parent) : QWidget(parent) , m_gradOpacity(1.0), m_stopIndex(-1), m_checkerPainter(4) , m_type(QGradient::LinearGradient), m_spread(QGradient::PadSpread) { setObjectName("KoGradientEditWidget"); // create a default gradient m_stops.append(QGradientStop(0.0, Qt::white)); m_stops.append(QGradientStop(1.0, Qt::green)); setupUI(); setupConnections(); updateUI(); } KoGradientEditWidget::~KoGradientEditWidget() { } void KoGradientEditWidget::setupUI() { QGridLayout* editLayout = new QGridLayout(this); int row = 0; editLayout->addWidget(new QLabel(i18n("Target:"), this), row, 0); m_gradientTarget = new QComboBox(this); m_gradientTarget->insertItem(0, i18n("Line")); m_gradientTarget->insertItem(1, i18n("Fill")); m_gradientTarget->setCurrentIndex(FillGradient); editLayout->addWidget(m_gradientTarget, row, 1, 1, 2); editLayout->addWidget(new QLabel(i18n("Type:"), this), ++row, 0); m_gradientType = new QComboBox(this); m_gradientType->insertItem(0, i18nc("Linear gradient type", "Linear")); m_gradientType->insertItem(1, i18nc("Radial gradient type", "Radial")); m_gradientType->insertItem(2, i18nc("Conical gradient type", "Conical")); editLayout->addWidget(m_gradientType, row, 1, 1, 2); editLayout->addWidget(new QLabel(i18n("Repeat:"), this), ++row, 0); m_gradientRepeat = new QComboBox(this); m_gradientRepeat->insertItem(0, i18nc("No gradient spread", "None")); m_gradientRepeat->insertItem(1, i18n("Reflect")); m_gradientRepeat->insertItem(2, i18n("Repeat")); editLayout->addWidget(m_gradientRepeat, row, 1, 1, 2); editLayout->addWidget(new QLabel(i18n("Overall opacity:"), this), ++row, 0); m_opacity = new KoSliderCombo(this); m_opacity->setDecimals(0); editLayout->addWidget(m_opacity, row, 1, 1, 2); editLayout->addWidget(new QLabel(i18n("Color stop:"), this), ++row, 0); m_stopColor = new QToolButton(this); editLayout->addWidget(m_stopColor, row, 1); m_stopPosition = new QDoubleSpinBox(this); m_stopPosition->setRange(0.0, 1.0); m_stopPosition->setSingleStep(0.01); editLayout->addWidget(m_stopPosition, row, 2); m_actionStopColor = new KoColorPopupAction(this); m_actionStopColor ->setToolTip(i18n("Stop color.")); m_stopColor->setDefaultAction(m_actionStopColor); m_addToPredefs = new QPushButton(i18n("&Add to Predefined Gradients"), this); editLayout->addWidget(m_addToPredefs, ++row, 0, 1, 3); editLayout->setSpacing(3); editLayout->setMargin(6); editLayout->setRowMinimumHeight(0, 12); editLayout->setRowStretch(++row, 1); } void KoGradientEditWidget::setupConnections() { connect(m_gradientType, SIGNAL(activated(int)), this, SLOT(combosChange(int))); connect(m_gradientRepeat, SIGNAL(activated(int)), this, SLOT(combosChange(int))); connect(m_gradientTarget, SIGNAL(activated(int)), this, SLOT(combosChange(int))); connect(m_addToPredefs, SIGNAL(clicked()), this, SLOT(addGradientToPredefs())); connect(m_opacity, SIGNAL(valueChanged(qreal,bool)), this, SLOT(opacityChanged(qreal,bool))); connect(m_actionStopColor, SIGNAL(colorChanged(KoColor)), this, SLOT(stopChanged())); connect(m_stopPosition, SIGNAL(valueChanged(double)), this, SLOT(stopChanged())); } void KoGradientEditWidget::blockChildSignals(bool block) { m_gradientType->blockSignals(block); m_gradientRepeat->blockSignals(block); m_addToPredefs->blockSignals(block); m_opacity->blockSignals(block); m_stopColor->blockSignals(block); m_stopPosition->blockSignals(block); } void KoGradientEditWidget::updateUI() { blockChildSignals(true); m_gradientType->setCurrentIndex(m_type); m_gradientRepeat->setCurrentIndex(m_spread); uint stopCount = m_stops.count(); qreal opacity = m_stops[0].second.alphaF(); bool equalOpacity = true; for (uint i = 1; i < stopCount; ++i) { if (opacity != m_stops[i].second.alphaF()) { equalOpacity = false; break; } } m_opacity->setEnabled(equalOpacity); if (equalOpacity) { m_opacity->setValue(opacity * 100); } // now update the stop color and opacity const bool colorStopSelected = m_stopIndex >= 0 && m_stopIndex < m_stops.count(); if (colorStopSelected) { QColor c = m_stops[m_stopIndex].second; m_stopPosition->setValue(m_stops[m_stopIndex].first); m_actionStopColor->setCurrentColor(c); } m_stopColor->setEnabled(colorStopSelected); m_stopPosition->setEnabled(colorStopSelected); blockChildSignals(false); } qreal KoGradientEditWidget::opacity() const { return m_opacity->value() / 100.0; } void KoGradientEditWidget::setOpacity(qreal opacity) { if (opacity < 0.0 || opacity > 1.0) return; m_gradOpacity = opacity; m_opacity->setValue(int(opacity*100.0)); } void KoGradientEditWidget::setStopIndex(int index) { m_stopIndex = index; updateUI(); } void KoGradientEditWidget::setGradient(const QGradient & gradient) { m_stops = gradient.stops(); m_type = gradient.type(); m_spread = gradient.spread(); updateUI(); } KoGradientEditWidget::GradientTarget KoGradientEditWidget::target() { return (GradientTarget)m_gradientTarget->currentIndex(); } void KoGradientEditWidget::setTarget(GradientTarget target) { m_gradientTarget->setCurrentIndex(target); } QGradient::Spread KoGradientEditWidget::spread() const { return m_spread; } void KoGradientEditWidget::setSpread(QGradient::Spread spread) { m_spread = spread; updateUI(); } QGradient::Type KoGradientEditWidget::type() const { return m_type; } void KoGradientEditWidget::setType(QGradient::Type type) { m_type = type; updateUI(); } QGradientStops KoGradientEditWidget::stops() const { return m_stops; } void KoGradientEditWidget::setStops(const QGradientStops &stops) { m_stops = stops; updateUI(); } void KoGradientEditWidget::combosChange(int) { m_type = static_cast(m_gradientType->currentIndex()); m_spread = static_cast(m_gradientRepeat->currentIndex()); emit changed(); } void KoGradientEditWidget::opacityChanged(qreal value, bool final) { Q_UNUSED(final); m_gradOpacity = value / 100.0; uint stopCount = m_stops.count(); for (uint i = 0; i < stopCount; ++i) m_stops[i].second.setAlphaF(m_gradOpacity); emit changed(); } void KoGradientEditWidget::addGradientToPredefs() { KoResourceServer* server = KoResourceServerProvider::instance()->gradientServer(); QString savePath = server->saveLocation(); int i = 1; QFileInfo fileInfo; do { fileInfo.setFile(savePath + QString("%1.svg").arg(i++, 4, 10, QChar('0'))); } while (fileInfo.exists()); QGradient * gradient = 0; switch (m_type) { case QGradient::LinearGradient: gradient = new QLinearGradient(); break; case QGradient::RadialGradient: gradient = new QRadialGradient(); break; case QGradient::ConicalGradient: gradient = new QConicalGradient(); break; default: // should not happen return; } gradient->setSpread(m_spread); gradient->setStops(m_stops); - KoStopGradient * g = KoStopGradient::fromQGradient(gradient); + QSharedPointer stopGradient = KoStopGradient::fromQGradient(gradient); delete gradient; - if (! g) + if (!stopGradient) { return; - g->setFilename(fileInfo.filePath()); - g->setValid(true); - - if (! server->addResource(g)) - delete g; + } + stopGradient->setFilename(fileInfo.filePath()); + stopGradient->setValid(true); } void KoGradientEditWidget::stopChanged() { if (m_stopIndex >= 0 && m_stopIndex < m_stops.count()) { m_stops[m_stopIndex].first = m_stopPosition->value(); m_stops[m_stopIndex].second = m_actionStopColor->currentColor(); emit changed(); } } diff --git a/libs/widgets/KoLegacyResourceModel.cpp b/libs/widgets/KoLegacyResourceModel.cpp index c779d098d8..85ef16e355 100644 --- a/libs/widgets/KoLegacyResourceModel.cpp +++ b/libs/widgets/KoLegacyResourceModel.cpp @@ -1,327 +1,328 @@ /* This file is part of the KDE project * Copyright (C) 2008-2009 Jan Hambrecht * Copyright (c) 2013 Sascha Suelzer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoLegacyResourceModel.h" #include #include #include #include #include KoLegacyResourceModel::KoLegacyResourceModel(QSharedPointer resourceAdapter, QObject * parent) : QAbstractTableModel(parent) , m_resourceAdapter(resourceAdapter) , m_columnCount(4) { Q_ASSERT(m_resourceAdapter); m_resourceAdapter->connectToResourceServer(); - connect(m_resourceAdapter.data(), SIGNAL(resourceAdded(KoResource*)), - this, SLOT(resourceAdded(KoResource*))); - connect(m_resourceAdapter.data(), SIGNAL(removingResource(KoResource*)), - this, SLOT(resourceRemoved(KoResource*))); - connect(m_resourceAdapter.data(), SIGNAL(resourceChanged(KoResource*)), - this, SLOT(resourceChanged(KoResource*))); + connect(m_resourceAdapter.data(), SIGNAL(resourceAdded(KoResourceSP)), + this, SLOT(resourceAdded(KoResourceSP))); + connect(m_resourceAdapter.data(), SIGNAL(removingResource(KoResourceSP)), + this, SLOT(resourceRemoved(KoResourceSP))); + connect(m_resourceAdapter.data(), SIGNAL(resourceChanged(KoResourceSP)), + this, SLOT(resourceChanged(KoResourceSP))); connect(m_resourceAdapter.data(), SIGNAL(tagsWereChanged()), this, SLOT(tagBoxEntryWasModified())); connect(m_resourceAdapter.data(), SIGNAL(tagCategoryWasAdded(QString)), this, SLOT(tagBoxEntryWasAdded(QString))); connect(m_resourceAdapter.data(), SIGNAL(tagCategoryWasRemoved(QString)), this, SLOT(tagBoxEntryWasRemoved(QString))); } KoLegacyResourceModel::~KoLegacyResourceModel() { if (!m_currentTag.isEmpty()) { KConfigGroup group = KSharedConfig::openConfig()->group("SelectedTags"); group.writeEntry(serverType(), m_currentTag); } } int KoLegacyResourceModel::rowCount( const QModelIndex &/*parent*/ ) const { int resourceCount = m_resourceAdapter->resources().count(); if (!resourceCount) return 0; return static_cast(ceil(static_cast(resourceCount) / m_columnCount)); } int KoLegacyResourceModel::columnCount ( const QModelIndex & ) const { return m_columnCount; } QVariant KoLegacyResourceModel::data( const QModelIndex &index, int role ) const { if( ! index.isValid() ) return QVariant(); switch( role ) { case Qt::DisplayRole: { - KoResource * resource = static_cast(index.internalPointer()); + KoResourceSP resource = KoResourceSP(static_cast(index.internalPointer())); if( ! resource ) return QVariant(); QString resName = i18n( resource->name().toUtf8().data()); return QVariant( resName ); } case KoLegacyResourceModel::TagsRole: { - KoResource * resource = static_cast(index.internalPointer()); + KoResourceSP resource = KoResourceSP(static_cast(index.internalPointer())); if( ! resource ) return QVariant(); if (m_resourceAdapter->assignedTagsList(resource).count()) { QString taglist = m_resourceAdapter->assignedTagsList(resource).join("
  • "); return QString("
  • %2
  • ").arg(taglist); } else { return QString(); } } case Qt::DecorationRole: { - KoResource * resource = static_cast(index.internalPointer()); + KoResourceSP resource = KoResourceSP(static_cast(index.internalPointer())); if( ! resource ) return QVariant(); return QVariant( resource->image() ); } case KoLegacyResourceModel::LargeThumbnailRole: { - KoResource * resource = static_cast(index.internalPointer()); + KoResourceSP resource = KoResourceSP(static_cast(index.internalPointer())); if( ! resource ) return QVariant(); QSize imageSize = resource->image().size(); QSize thumbSize( 100, 100 ); if(imageSize.height() > thumbSize.height() || imageSize.width() > thumbSize.width()) { qreal scaleW = static_cast( thumbSize.width() ) / static_cast( imageSize.width() ); qreal scaleH = static_cast( thumbSize.height() ) / static_cast( imageSize.height() ); qreal scale = qMin( scaleW, scaleH ); int thumbW = static_cast( imageSize.width() * scale ); int thumbH = static_cast( imageSize.height() * scale ); return QVariant(resource->image().scaled( thumbW, thumbH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); } else return QVariant(resource->image()); } default: return QVariant(); } } QModelIndex KoLegacyResourceModel::index ( int row, int column, const QModelIndex & ) const { int index = row * m_columnCount + column; - const QList resources = m_resourceAdapter->resources(); - if( index >= resources.count() || index < 0) + const QList resources = m_resourceAdapter->resources(); + if( index >= resources.count() || index < 0) { return QModelIndex(); + } - return createIndex( row, column, resources[index] ); + return createIndex(row, column, resources[index].data()); } -void KoLegacyResourceModel::doSafeLayoutReset(KoResource *activateAfterReformat) +void KoLegacyResourceModel::doSafeLayoutReset(KoResourceSP activateAfterReformat) { emit beforeResourcesLayoutReset(activateAfterReformat); beginResetModel(); endResetModel(); emit afterResourcesLayoutReset(); } void KoLegacyResourceModel::setColumnCount( int columnCount ) { if (columnCount != m_columnCount) { emit beforeResourcesLayoutReset(0); m_columnCount = columnCount; beginResetModel(); endResetModel(); emit afterResourcesLayoutReset(); } } -void KoLegacyResourceModel::resourceAdded(KoResource *resource) +void KoLegacyResourceModel::resourceAdded(KoResourceSP resource) { int newIndex = m_resourceAdapter->resources().indexOf(resource); if (newIndex >= 0) { doSafeLayoutReset(0); } } -void KoLegacyResourceModel::resourceRemoved(KoResource *resource) +void KoLegacyResourceModel::resourceRemoved(KoResourceSP resource) { Q_UNUSED(resource); doSafeLayoutReset(0); } -void KoLegacyResourceModel::resourceChanged(KoResource* resource) +void KoLegacyResourceModel::resourceChanged(KoResourceSP resource) { int resourceIndex = m_resourceAdapter->resources().indexOf(resource); int row = resourceIndex / columnCount(); int column = resourceIndex % columnCount(); QModelIndex modelIndex = index(row, column); if (!modelIndex.isValid()) { return; } emit dataChanged(modelIndex, modelIndex); } void KoLegacyResourceModel::tagBoxEntryWasModified() { m_resourceAdapter->updateServer(); emit tagBoxEntryModified(); } void KoLegacyResourceModel::tagBoxEntryWasAdded(const QString& tag) { emit tagBoxEntryAdded(tag); } void KoLegacyResourceModel::tagBoxEntryWasRemoved(const QString& tag) { emit tagBoxEntryRemoved(tag); } -QModelIndex KoLegacyResourceModel::indexFromResource(KoResource* resource) const +QModelIndex KoLegacyResourceModel::indexFromResource(KoResourceSP resource) const { int resourceIndex = m_resourceAdapter->resources().indexOf(resource); if (columnCount() > 0) { int row = resourceIndex / columnCount(); int column = resourceIndex % columnCount(); return index(row, column); } return QModelIndex(); } QString KoLegacyResourceModel::extensions() const { return m_resourceAdapter->extensions(); } void KoLegacyResourceModel::importResourceFile(const QString &filename) { m_resourceAdapter->importResourceFile(filename); } void KoLegacyResourceModel::importResourceFile(const QString & filename, bool fileCreation) { m_resourceAdapter->importResourceFile(filename, fileCreation); } -bool KoLegacyResourceModel::removeResource(KoResource* resource) +bool KoLegacyResourceModel::removeResource(KoResourceSP resource) { return m_resourceAdapter->removeResource(resource); } void KoLegacyResourceModel::removeResourceFile(const QString &filename) { m_resourceAdapter->removeResourceFile(filename); } -QStringList KoLegacyResourceModel::assignedTagsList(KoResource *resource) const +QStringList KoLegacyResourceModel::assignedTagsList(KoResourceSP resource) const { return m_resourceAdapter->assignedTagsList(resource); } -void KoLegacyResourceModel::addTag(KoResource* resource, const QString& tag) +void KoLegacyResourceModel::addTag(KoResourceSP resource, const QString& tag) { m_resourceAdapter->addTag(resource, tag); emit tagBoxEntryAdded(tag); } -void KoLegacyResourceModel::deleteTag(KoResource *resource, const QString &tag) +void KoLegacyResourceModel::deleteTag(KoResourceSP resource, const QString &tag) { m_resourceAdapter->deleteTag(resource, tag); } QStringList KoLegacyResourceModel::tagNamesList() const { return m_resourceAdapter->tagNamesList(); } QStringList KoLegacyResourceModel::searchTag(const QString& lineEditText) { return m_resourceAdapter->searchTag(lineEditText); } void KoLegacyResourceModel::searchTextChanged(const QString& searchString) { m_resourceAdapter->searchTextChanged(searchString); } void KoLegacyResourceModel::enableResourceFiltering(bool enable) { m_resourceAdapter->enableResourceFiltering(enable); } void KoLegacyResourceModel::setCurrentTag(const QString& currentTag) { m_currentTag = currentTag; m_resourceAdapter->setCurrentTag(currentTag); } void KoLegacyResourceModel::updateServer() { m_resourceAdapter->updateServer(); } int KoLegacyResourceModel::resourcesCount() const { return m_resourceAdapter->resources().count(); } -QList KoLegacyResourceModel::currentlyVisibleResources() const +QList KoLegacyResourceModel::currentlyVisibleResources() const { return m_resourceAdapter->resources(); } void KoLegacyResourceModel::tagCategoryMembersChanged() { m_resourceAdapter->tagCategoryMembersChanged(); } void KoLegacyResourceModel::tagCategoryAdded(const QString& tag) { m_resourceAdapter->tagCategoryAdded(tag); } void KoLegacyResourceModel::tagCategoryRemoved(const QString& tag) { m_resourceAdapter->tagCategoryRemoved(tag); } QString KoLegacyResourceModel::serverType() const { return m_resourceAdapter->serverType(); } -QList< KoResource* > KoLegacyResourceModel::serverResources() const +QList< KoResourceSP > KoLegacyResourceModel::serverResources() const { return m_resourceAdapter->serverResources(); } diff --git a/libs/widgets/KoLegacyResourceModel.h b/libs/widgets/KoLegacyResourceModel.h index 4f9b6e5244..83ed48ac8a 100644 --- a/libs/widgets/KoLegacyResourceModel.h +++ b/libs/widgets/KoLegacyResourceModel.h @@ -1,112 +1,113 @@ /* This file is part of the KDE project * Copyright (C) 2008 Jan Hambrecht * Copyright (c) 2013 Sascha Suelzer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOLEGACYRESOURCEMODEL_H #define KOLEGACYRESOURCEMODEL_H #include - #include "QAbstractTableModel" +#include + #include "kritawidgets_export.h" class KoAbstractResourceServerAdapter; class KoResource; /// The resource model managing the resource data class KRITAWIDGETS_EXPORT KoLegacyResourceModel : public QAbstractTableModel { Q_OBJECT public: explicit KoLegacyResourceModel(QSharedPointer resourceAdapter, QObject * parent = 0); ~KoLegacyResourceModel() override; /// reimplemented int rowCount(const QModelIndex &parent = QModelIndex()) const override; /// reimplemented int columnCount ( const QModelIndex & parent = QModelIndex() ) const override; /// reimplemented QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; /// reimplemented QModelIndex index ( int row, int column = 0, const QModelIndex & parent = QModelIndex() ) const override; /// Sets the number of columns to display void setColumnCount( int columnCount ); /// Extensions to Qt::ItemDataRole. enum ItemDataRole { /// A larger thumbnail for displaying in a tooltip. 200x200 or so. LargeThumbnailRole = Qt::UserRole + 1, TagsRole }; - QModelIndex indexFromResource(KoResource* resource) const; + QModelIndex indexFromResource(KoResourceSP resource) const; /// facade for KoAbstractResourceServerAdapter QString extensions() const; void importResourceFile(const QString &filename); void importResourceFile(const QString &filename, bool fileCreation); - bool removeResource(KoResource* resource); + bool removeResource(KoResourceSP resource); void removeResourceFile(const QString & filename); - QStringList assignedTagsList(KoResource *resource) const; - void addTag(KoResource* resource, const QString& tag); - void deleteTag( KoResource* resource, const QString& tag); + QStringList assignedTagsList(KoResourceSP resource) const; + void addTag(KoResourceSP resource, const QString& tag); + void deleteTag( KoResourceSP resource, const QString& tag); QStringList tagNamesList() const; QStringList searchTag(const QString& lineEditText); void enableResourceFiltering(bool enable); void setCurrentTag(const QString& currentTag); void searchTextChanged(const QString& searchString); void updateServer(); int resourcesCount() const; - QList currentlyVisibleResources() const; - QList serverResources() const; + QList currentlyVisibleResources() const; + QList serverResources() const; void tagCategoryMembersChanged(); void tagCategoryAdded(const QString& tag); void tagCategoryRemoved(const QString& tag); QString serverType() const; Q_SIGNALS: /// XXX: not sure if this is the best place for these void tagBoxEntryModified(); void tagBoxEntryAdded(const QString& tag); void tagBoxEntryRemoved(const QString& tag); - void beforeResourcesLayoutReset(KoResource *activateAfterReformat); + void beforeResourcesLayoutReset(KoResourceSP activateAfterReformat); void afterResourcesLayoutReset(); private: - void doSafeLayoutReset(KoResource *activateAfterReformat); + void doSafeLayoutReset(KoResourceSP activateAfterReformat); private Q_SLOTS: - void resourceAdded(KoResource *resource); - void resourceRemoved(KoResource *resource); - void resourceChanged(KoResource *resource); + void resourceAdded(KoResourceSP resource); + void resourceRemoved(KoResourceSP resource); + void resourceChanged(KoResourceSP resource); void tagBoxEntryWasModified(); void tagBoxEntryWasAdded(const QString& tag); void tagBoxEntryWasRemoved(const QString& tag); private: QSharedPointer m_resourceAdapter; int m_columnCount; QString m_currentTag; }; #endif // KoLegacyResourceModel_H diff --git a/libs/widgets/KoResourceFiltering.cpp b/libs/widgets/KoResourceFiltering.cpp index 03fd8b6f7f..d86ab1334d 100644 --- a/libs/widgets/KoResourceFiltering.cpp +++ b/libs/widgets/KoResourceFiltering.cpp @@ -1,261 +1,261 @@ /* This file is part of the KDE project Copyright (c) 2013 Sascha Suelzer 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 "KoResourceFiltering.h" #include "KoResourceServer.h" #include #include class Q_DECL_HIDDEN KoResourceFiltering::Private { public: Private() : isTag("\\[([\\w\\s]+)\\]") , isExactMatch("\"([\\w\\s]+)\"") , searchTokenizer("\\s*,+\\s*") , hasNewFilters(false) , name(true) , filename(true) , resourceServer(0) {} QRegExp isTag; QRegExp isExactMatch; QRegExp searchTokenizer; bool hasNewFilters; bool name,filename; KoResourceServerBase *resourceServer; QStringList tagSetFilenames; QStringList includedNames; QStringList excludedNames; QString currentTag; }; KoResourceFiltering::KoResourceFiltering() : d(new Private()) {} KoResourceFiltering::~KoResourceFiltering() { delete d; } void KoResourceFiltering::configure(int filterType, bool enable) { switch (filterType) { case 0: d->name=true; d->filename=enable; break; case 1: d->name=enable; break; case 2: d->filename=enable; break; } } void KoResourceFiltering::setChanged() { d->hasNewFilters = true; } void KoResourceFiltering::setTagSetFilenames(const QStringList& filenames) { d->tagSetFilenames = filenames; d->excludedNames.clear(); d->includedNames.clear(); setChanged(); } bool KoResourceFiltering::matchesResource(const QStringList &filteredList,const QStringList &filterList) const { Qt::CaseSensitivity sensitivity = Qt::CaseInsensitive; foreach (QString filter, filterList) { if (!filter.startsWith('"')) { foreach (QString filtered, filteredList) { if (filtered.contains(filter,sensitivity)) { return true; } } } else if (d->name) { filter.remove('"'); if (!filteredList.at(0).compare(filter)) { return true; } } } return false; } void KoResourceFiltering::sanitizeExclusionList() { if(!d->includedNames.isEmpty()) { foreach (const QString &exclusion, d->excludedNames) { if (!excludeFilterIsValid(exclusion)) d->excludedNames.removeAll(exclusion); } } } QStringList KoResourceFiltering::tokenizeSearchString(const QString& searchString) const { return searchString.split(d->searchTokenizer, QString::SkipEmptyParts); } void KoResourceFiltering::populateIncludeExcludeFilters(const QStringList& filteredNames) { foreach (QString name, filteredNames) { QStringList* target; if(name.startsWith('!')) { name.remove('!'); target = &d->excludedNames; } else { target = &d->includedNames; } if(!name.isEmpty()) { if (name.startsWith('[')) { if (d->isTag.exactMatch(name) && d->resourceServer) { name = d->isTag.cap(1); (*target) += d->resourceServer->queryResources(name); } } else if (name.startsWith('"')) { if (d->isExactMatch.exactMatch(name)) { target->push_back(name); } } else { target->push_back(name); } } } sanitizeExclusionList(); } bool KoResourceFiltering::hasFilters() const { return (!d->tagSetFilenames.isEmpty() || !d->includedNames.isEmpty() || !d->excludedNames.isEmpty()); } bool KoResourceFiltering::filtersHaveChanged() const { return d->hasNewFilters; } void KoResourceFiltering::setFilters(const QString &searchString) { d->excludedNames.clear(); d->includedNames.clear(); QStringList filteredNames = tokenizeSearchString(searchString); populateIncludeExcludeFilters(filteredNames); setChanged(); } -bool KoResourceFiltering::presetMatchesSearch(KoResource * resource) const +bool KoResourceFiltering::presetMatchesSearch(KoResourceSP resource) const { QList filteredList; QString resourceFileName = resource->shortFilename(); QString resourceName = resource->name(); if (d->name) { filteredList.push_front(resourceName); } if (d->filename) { filteredList.push_back(resourceFileName); } if (matchesResource(filteredList,d->excludedNames)) { return false; } if (matchesResource(filteredList,d->includedNames)) { return true; } foreach (const QString &filter, d->tagSetFilenames) { if (!resourceFileName.compare(filter) || !resourceName.compare(filter)) { return true; } } return false; } void KoResourceFiltering::setInclusions(const QStringList &inclusions) { d->includedNames = inclusions; setChanged(); } void KoResourceFiltering::setExclusions(const QStringList &exclusions) { d->excludedNames = exclusions; setChanged(); } bool KoResourceFiltering::excludeFilterIsValid(const QString &exclusion) { Q_FOREACH (const QString &inclusion, d->includedNames) { if ((inclusion.startsWith(exclusion) && exclusion.size() <= inclusion.size())) { return false; } } return true; } -QList< KoResource* > KoResourceFiltering::filterResources(QList< KoResource* > resources) +QList< KoResourceSP > KoResourceFiltering::filterResources(QList< KoResourceSP > resources) { - Q_FOREACH (KoResource* resource, resources) { + Q_FOREACH (KoResourceSP resource, resources) { if(!presetMatchesSearch(resource)) { resources.removeAll(resource); } } setDoneFiltering(); return resources; } void KoResourceFiltering::setDoneFiltering() { d->hasNewFilters = false; } void KoResourceFiltering::rebuildCurrentTagFilenames() { d->tagSetFilenames = d->resourceServer->queryResources(d->currentTag); } void KoResourceFiltering::setCurrentTag(const QString& tagSet) { d->currentTag = tagSet; rebuildCurrentTagFilenames(); } void KoResourceFiltering::setResourceServer(KoResourceServerBase* resourceServer) { d->resourceServer = resourceServer; } diff --git a/libs/widgets/KoResourceFiltering.h b/libs/widgets/KoResourceFiltering.h index 10f16d7869..e53d83f7a1 100644 --- a/libs/widgets/KoResourceFiltering.h +++ b/libs/widgets/KoResourceFiltering.h @@ -1,67 +1,68 @@ /* This file is part of the KDE project Copyright (c) 2013 Sascha Suelzer 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 KORESOURCEFILTER_H #define KORESOURCEFILTER_H #include "kritawidgets_export.h" #include +#include + class KoResourceServerBase; -class KoResource; class QStringList; class QString; class KRITAWIDGETS_EXPORT KoResourceFiltering { public: KoResourceFiltering(); virtual ~KoResourceFiltering(); void configure(int filterType, bool enable); bool hasFilters() const; bool filtersHaveChanged() const; void setTagSetFilenames(const QStringList& filenames); void setCurrentTag(const QString& tagSet); void rebuildCurrentTagFilenames(); void setResourceServer(KoResourceServerBase *resourceServer); void setFilters(const QString& searchString); - QList filterResources(QList< KoResource* > resources); + QList filterResources(QList< KoResourceSP > resources); void setInclusions(const QStringList &inclusions); void setExclusions(const QStringList &exclusions); private: void setDoneFiltering(); - bool presetMatchesSearch(KoResource * resource) const; + bool presetMatchesSearch(KoResourceSP resource) const; void setChanged(); bool excludeFilterIsValid(const QString &exclusion); bool matchesResource(const QStringList& filtered,const QStringList &filterList) const; void populateIncludeExcludeFilters(const QStringList& filteredNames); void sanitizeExclusionList(); QStringList tokenizeSearchString(const QString& searchString) const; class Private; Private * const d; }; #endif // KORESOURCEFILTER_H diff --git a/libs/widgets/KoResourceItemChooser.cpp b/libs/widgets/KoResourceItemChooser.cpp index 13831a8b08..2af61476a2 100644 --- a/libs/widgets/KoResourceItemChooser.cpp +++ b/libs/widgets/KoResourceItemChooser.cpp @@ -1,587 +1,587 @@ /* This file is part of the KDE project Copyright (c) 2002 Patrick Julien Copyright (c) 2007 Jan Hambrecht Copyright (c) 2007 Sven Langkamp Copyright (C) 2011 Srikanth Tiyyagura Copyright (c) 2011 José Luis Vergara Copyright (c) 2013 Sascha Suelzer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoResourceItemChooser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KoResourceServerAdapter.h" #include "KoResourceItemView.h" #include "KoResourceItemDelegate.h" #include "KoLegacyResourceModel.h" #include #include "KoResourceTaggingManager.h" #include "KoTagFilterWidget.h" #include "KoTagChooserWidget.h" #include "KoResourceItemChooserSync.h" #include "kis_assert.h" #include class Q_DECL_HIDDEN KoResourceItemChooser::Private { public: Private() : model(0) , view(0) , buttonGroup(0) , viewModeButton(0) , usePreview(false) , previewScroller(0) , previewLabel(0) , splitter(0) , tiledPreview(false) , grayscalePreview(false) , synced(false) , updatesBlocked(false) , savedResourceWhileReset(0) {} KoLegacyResourceModel *model; KoResourceTaggingManager *tagManager; KoResourceItemView *view; QButtonGroup *buttonGroup; QToolButton *viewModeButton; bool usePreview; QScrollArea *previewScroller; QLabel *previewLabel; QSplitter *splitter; QGridLayout *buttonLayout; bool tiledPreview; bool grayscalePreview; bool synced; bool updatesBlocked; - KoResource *savedResourceWhileReset; + KoResourceSP savedResourceWhileReset; QList customButtons; }; KoResourceItemChooser::KoResourceItemChooser(QSharedPointer resourceAdapter, QWidget *parent, bool usePreview) : QWidget(parent) , d(new Private()) { Q_ASSERT(resourceAdapter); d->splitter = new QSplitter(this); d->model = new KoLegacyResourceModel(resourceAdapter, this); - connect(d->model, SIGNAL(beforeResourcesLayoutReset(KoResource*)), SLOT(slotBeforeResourcesLayoutReset(KoResource*))); + connect(d->model, SIGNAL(beforeResourcesLayoutReset(KoResourceSP )), SLOT(slotBeforeResourcesLayoutReset(KoResourceSP ))); connect(d->model, SIGNAL(afterResourcesLayoutReset()), SLOT(slotAfterResourcesLayoutReset())); d->view = new KoResourceItemView(this); d->view->setObjectName("ResourceItemview"); d->view->setModel(d->model); d->view->setItemDelegate(new KoResourceItemDelegate(this)); d->view->setSelectionMode(QAbstractItemView::SingleSelection); d->view->viewport()->installEventFilter(this); connect(d->view, SIGNAL(currentResourceChanged(QModelIndex)), this, SLOT(activated(QModelIndex))); connect(d->view, SIGNAL(currentResourceClicked(QModelIndex)), this, SLOT(clicked(QModelIndex))); connect(d->view, SIGNAL(contextMenuRequested(QPoint)), this, SLOT(contextMenuRequested(QPoint))); connect(d->view, SIGNAL(sigSizeChanged()), this, SLOT(updateView())); d->splitter->addWidget(d->view); d->splitter->setStretchFactor(0, 2); d->usePreview = usePreview; if (d->usePreview) { d->previewScroller = new QScrollArea(this); d->previewScroller->setWidgetResizable(true); d->previewScroller->setBackgroundRole(QPalette::Dark); d->previewScroller->setVisible(true); d->previewScroller->setAlignment(Qt::AlignCenter); d->previewLabel = new QLabel(this); d->previewScroller->setWidget(d->previewLabel); d->splitter->addWidget(d->previewScroller); if (d->splitter->count() == 2) { d->splitter->setSizes(QList() << 280 << 160); } QScroller* scroller = KisKineticScroller::createPreconfiguredScroller(d->previewScroller); if (scroller) { connect(scroller, SIGNAL(stateChanged(QScroller::State)), this, SLOT(slotScrollerStateChanged(QScroller::State))); } } d->splitter->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); connect(d->splitter, SIGNAL(splitterMoved(int,int)), SIGNAL(splitterMoved())); d->buttonGroup = new QButtonGroup(this); d->buttonGroup->setExclusive(false); QGridLayout *layout = new QGridLayout(this); d->buttonLayout = new QGridLayout(); importButton = new QPushButton(this); importButton->setToolTip(i18nc("@info:tooltip", "Import resource")); importButton->setEnabled(true); d->buttonGroup->addButton(importButton, Button_Import); d->buttonLayout->addWidget(importButton, 0, 0); deleteButton = new QPushButton(this); deleteButton->setToolTip(i18nc("@info:tooltip", "Delete resource")); deleteButton->setEnabled(false); d->buttonGroup->addButton(deleteButton, Button_Remove); d->buttonLayout->addWidget(deleteButton, 0, 1); connect(d->buttonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotButtonClicked(int))); d->buttonLayout->setColumnStretch(0, 1); d->buttonLayout->setColumnStretch(1, 1); d->buttonLayout->setColumnStretch(2, 2); d->buttonLayout->setSpacing(0); d->buttonLayout->setMargin(0); d->viewModeButton = new QToolButton(this); d->viewModeButton->setPopupMode(QToolButton::InstantPopup); d->viewModeButton->setVisible(false); d->tagManager = new KoResourceTaggingManager(d->model, this); connect(d->tagManager, SIGNAL(updateView()), this, SLOT(updateView())); layout->addWidget(d->tagManager->tagChooserWidget(), 0, 0); layout->addWidget(d->viewModeButton, 0, 1); layout->addWidget(d->splitter, 1, 0, 1, 2); layout->addWidget(d->tagManager->tagFilterWidget(), 2, 0, 1, 2); layout->addLayout(d->buttonLayout, 3, 0, 1, 2); layout->setMargin(0); layout->setSpacing(0); updateView(); updateButtonState(); showTaggingBar(false); activated(d->model->index(0, 0)); } KoResourceItemChooser::~KoResourceItemChooser() { disconnect(); delete d; } void KoResourceItemChooser::slotButtonClicked(int button) { if (button == Button_Import) { QString extensions = d->model->extensions(); QStringList mimeTypes; Q_FOREACH(const QString &suffix, extensions.split(":")) { mimeTypes << KisMimeDatabase::mimeTypeForSuffix(suffix); } KoFileDialog dialog(0, KoFileDialog::OpenFile, "OpenDocument"); dialog.setMimeTypeFilters(mimeTypes); dialog.setCaption(i18nc("@title:window", "Choose File to Add")); QString filename = dialog.filename(); d->model->importResourceFile(filename); } else if (button == Button_Remove) { QModelIndex index = d->view->currentIndex(); int row = index.row(); int column = index.column(); if (index.isValid()) { - KoResource *resource = resourceFromModelIndex(index); + KoResourceSP resource = resourceFromModelIndex(index); if (resource) { d->model->removeResource(resource); } } if (column == 0) { int rowMin = --row; row = qBound(0, rowMin, row); } int columnMin = --column; column = qBound(0, columnMin, column); setCurrentItem(row, column); activated(d->model->index(row, column)); } updateButtonState(); } void KoResourceItemChooser::showButtons(bool show) { foreach (QAbstractButton * button, d->buttonGroup->buttons()) { show ? button->show() : button->hide(); } Q_FOREACH (QAbstractButton *button, d->customButtons) { show ? button->show() : button->hide(); } } void KoResourceItemChooser::addCustomButton(QAbstractButton *button, int cell) { d->buttonLayout->addWidget(button, 0, cell); d->buttonLayout->setColumnStretch(2, 1); d->buttonLayout->setColumnStretch(3, 1); } void KoResourceItemChooser::showTaggingBar(bool show) { d->tagManager->showTaggingBar(show); } void KoResourceItemChooser::setRowCount(int rowCount) { int resourceCount = d->model->resourcesCount(); d->model->setColumnCount(static_cast(resourceCount) / rowCount); //Force an update to get the right row height (in theory) QRect geometry = d->view->geometry(); d->view->setViewMode(KoResourceItemView::FIXED_ROWS); d->view->setGeometry(geometry.adjusted(0, 0, 0, 1)); d->view->setGeometry(geometry); } void KoResourceItemChooser::setColumnCount(int columnCount) { d->model->setColumnCount(columnCount); } void KoResourceItemChooser::setRowHeight(int rowHeight) { d->view->verticalHeader()->setDefaultSectionSize(rowHeight); } void KoResourceItemChooser::setColumnWidth(int columnWidth) { d->view->horizontalHeader()->setDefaultSectionSize(columnWidth); } void KoResourceItemChooser::setItemDelegate(QAbstractItemDelegate *delegate) { d->view->setItemDelegate(delegate); } -KoResource *KoResourceItemChooser::currentResource() const +KoResourceSP KoResourceItemChooser::currentResource() const { QModelIndex index = d->view->currentIndex(); if (index.isValid()) { return resourceFromModelIndex(index); } return 0; } -void KoResourceItemChooser::setCurrentResource(KoResource *resource) +void KoResourceItemChooser::setCurrentResource(KoResourceSP resource) { // don't update if the change came from the same chooser if (d->updatesBlocked) { return; } QModelIndex index = d->model->indexFromResource(resource); d->view->setCurrentIndex(index); updatePreview(index.isValid() ? resource : 0); } -void KoResourceItemChooser::slotBeforeResourcesLayoutReset(KoResource *activateAfterReset) +void KoResourceItemChooser::slotBeforeResourcesLayoutReset(KoResourceSP activateAfterReset) { d->savedResourceWhileReset = activateAfterReset ? activateAfterReset : currentResource(); } void KoResourceItemChooser::slotAfterResourcesLayoutReset() { if (d->savedResourceWhileReset) { this->blockSignals(true); setCurrentResource(d->savedResourceWhileReset); this->blockSignals(false); } } void KoResourceItemChooser::setPreviewOrientation(Qt::Orientation orientation) { d->splitter->setOrientation(orientation); } void KoResourceItemChooser::setPreviewTiled(bool tiled) { d->tiledPreview = tiled; } void KoResourceItemChooser::setGrayscalePreview(bool grayscale) { d->grayscalePreview = grayscale; } void KoResourceItemChooser::setCurrentItem(int row, int column) { QModelIndex index = d->model->index(row, column); if (!index.isValid()) return; d->view->setCurrentIndex(index); if (index.isValid()) { updatePreview(resourceFromModelIndex(index)); } } void KoResourceItemChooser::setProxyModel(QAbstractProxyModel *proxyModel) { proxyModel->setSourceModel(d->model); d->view->setModel(proxyModel); } void KoResourceItemChooser::activated(const QModelIndex &index) { if (!index.isValid()) return; - KoResource *resource = 0; + KoResourceSP resource = 0; if (index.isValid()) { resource = resourceFromModelIndex(index); } KIS_SAFE_ASSERT_RECOVER (resource) { resource = currentResource(); } if (resource) { d->updatesBlocked = true; emit resourceSelected(resource); d->updatesBlocked = false; updatePreview(resource); updateButtonState(); } } void KoResourceItemChooser::clicked(const QModelIndex &index) { Q_UNUSED(index); - KoResource *resource = currentResource(); + KoResourceSP resource = currentResource(); if (resource) { emit resourceClicked(resource); } } void KoResourceItemChooser::updateButtonState() { QAbstractButton *removeButton = d->buttonGroup->button(Button_Remove); if (! removeButton) return; - KoResource *resource = currentResource(); + KoResourceSP resource = currentResource(); if (resource) { removeButton->setEnabled(!resource->permanent()); return; } removeButton->setEnabled(false); } -void KoResourceItemChooser::updatePreview(KoResource *resource) +void KoResourceItemChooser::updatePreview(KoResourceSP resource) { if (!d->usePreview) return; if (!resource) { d->previewLabel->setPixmap(QPixmap()); return; } QImage image = resource->image(); if (image.format() != QImage::Format_RGB32 && image.format() != QImage::Format_ARGB32 && image.format() != QImage::Format_ARGB32_Premultiplied) { image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); } if (d->tiledPreview) { int width = d->previewScroller->width() * 4; int height = d->previewScroller->height() * 4; QImage img(width, height, image.format()); QPainter gc(&img); gc.fillRect(img.rect(), Qt::white); gc.setPen(Qt::NoPen); gc.setBrush(QBrush(image)); gc.drawRect(img.rect()); image = img; } // Only convert to grayscale if it is rgb. Otherwise, it's gray already. if (d->grayscalePreview && !image.isGrayscale()) { QRgb *pixel = reinterpret_cast(image.bits()); for (int row = 0; row < image.height(); ++row) { for (int col = 0; col < image.width(); ++col) { const QRgb currentPixel = pixel[row * image.width() + col]; const int red = qRed(currentPixel); const int green = qGreen(currentPixel); const int blue = qBlue(currentPixel); const int grayValue = (red * 11 + green * 16 + blue * 5) / 32; pixel[row * image.width() + col] = qRgb(grayValue, grayValue, grayValue); } } } d->previewLabel->setPixmap(QPixmap::fromImage(image)); } -KoResource *KoResourceItemChooser::resourceFromModelIndex(const QModelIndex &index) const +KoResourceSP KoResourceItemChooser::resourceFromModelIndex(const QModelIndex &index) const { if (!index.isValid()) return 0; const QAbstractProxyModel *proxyModel = dynamic_cast(index.model()); if (proxyModel) { //Get original model index, because proxy models destroy the internalPointer QModelIndex originalIndex = proxyModel->mapToSource(index); - return static_cast(originalIndex.internalPointer()); + return KoResourceSP(static_cast(originalIndex.internalPointer())); } - return static_cast(index.internalPointer()); + return KoResourceSP(static_cast(index.internalPointer())); } QSize KoResourceItemChooser::viewSize() const { return d->view->size(); } KoResourceItemView *KoResourceItemChooser::itemView() const { return d->view; } void KoResourceItemChooser::contextMenuRequested(const QPoint &pos) { d->tagManager->contextMenuRequested(currentResource(), pos); } void KoResourceItemChooser::setViewModeButtonVisible(bool visible) { d->viewModeButton->setVisible(visible); } QToolButton *KoResourceItemChooser::viewModeButton() const { return d->viewModeButton; } void KoResourceItemChooser::setSynced(bool sync) { if (d->synced == sync) return; d->synced = sync; KoResourceItemChooserSync *chooserSync = KoResourceItemChooserSync::instance(); if (sync) { connect(chooserSync, SIGNAL(baseLengthChanged(int)), SLOT(baseLengthChanged(int))); baseLengthChanged(chooserSync->baseLength()); } else { chooserSync->disconnect(this); } } void KoResourceItemChooser::baseLengthChanged(int length) { if (d->synced) { int resourceCount = d->model->resourcesCount(); int width = d->view->width(); int maxColumns = width / length; int cols = width / (2 * length) + 1; while (cols <= maxColumns) { int size = width / cols; int rows = ceil(resourceCount / (double)cols); if (rows * size < (d->view->height() - 5)) { break; } cols++; } setColumnCount(cols); } d->view->updateView(); } bool KoResourceItemChooser::eventFilter(QObject *object, QEvent *event) { if (d->synced && event->type() == QEvent::Wheel) { KoResourceItemChooserSync *chooserSync = KoResourceItemChooserSync::instance(); QWheelEvent *qwheel = static_cast(event); if (qwheel->modifiers() & Qt::ControlModifier) { int degrees = qwheel->delta() / 8; int newBaseLength = chooserSync->baseLength() + degrees / 15 * 10; chooserSync->setBaseLength(newBaseLength); return true; } } return QObject::eventFilter(object, event); } void KoResourceItemChooser::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); updateView(); } void KoResourceItemChooser::showEvent(QShowEvent *event) { QWidget::showEvent(event); updateView(); /* Give the search field focus onShowEvent to allow for * faster preset filtering... */ if( d->tagManager ) { d->tagManager->searchField()->setFocus(Qt::FocusReason::OtherFocusReason); d->tagManager->searchField()->selectAll(); } } void KoResourceItemChooser::updateView() { if (d->synced) { KoResourceItemChooserSync *chooserSync = KoResourceItemChooserSync::instance(); baseLengthChanged(chooserSync->baseLength()); } /// helps to set icons here in case the theme is changed d->viewModeButton->setIcon(koIcon("view-choose")); importButton->setIcon(koIcon("document-open")); deleteButton->setIcon(koIcon("trash-empty")); } diff --git a/libs/widgets/KoResourceItemChooser.h b/libs/widgets/KoResourceItemChooser.h index de994e7c1c..ec9698aef3 100644 --- a/libs/widgets/KoResourceItemChooser.h +++ b/libs/widgets/KoResourceItemChooser.h @@ -1,158 +1,159 @@ /* This file is part of the KDE project Copyright (c) 2002 Patrick Julien Copyright (c) 2007 Jan Hambrecht Copyright (c) 2007 Sven Langkamp Copyright (c) 2010 Boudewijn Rempt Copyright (C) 2011 Srikanth Tiyyagura Copyright (c) 2011 José Luis Vergara Copyright (c) 2013 Sascha Suelzer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KO_RESOURCE_ITEM_CHOOSER #define KO_RESOURCE_ITEM_CHOOSER #include #include #include "kritawidgets_export.h" #include +#include + class QModelIndex; class QAbstractProxyModel; class QAbstractItemDelegate; class QAbstractButton; class QToolButton; class KoAbstractResourceServerAdapter; class KoResourceItemView; -class KoResource; /** * A widget that contains a KoResourceChooser as well * as an import/export button */ class KRITAWIDGETS_EXPORT KoResourceItemChooser : public QWidget { Q_OBJECT public: enum Buttons { Button_Import, Button_Remove }; /// \p usePreview shows the aside preview with the resource's image explicit KoResourceItemChooser(QSharedPointer resourceAdapter, QWidget *parent = 0, bool usePreview = false); ~KoResourceItemChooser() override; /// Sets number of columns in the view and causes the number of rows to be calculated accordingly void setColumnCount(int columnCount); /// Sets number of rows in the view and causes the number of columns to be calculated accordingly void setRowCount(int rowCount); /// Sets the height of the view rows void setRowHeight(int rowHeight); /// Sets the width of the view columns void setColumnWidth(int columnWidth); /// Sets a custom delegate for the view void setItemDelegate(QAbstractItemDelegate *delegate); /// Gets the currently selected resource /// @returns the selected resource, 0 is no resource is selected - KoResource *currentResource() const; + KoResourceSP currentResource() const; /// Sets the item representing the resource as selected - void setCurrentResource(KoResource *resource); + void setCurrentResource(KoResourceSP resource); /** * Sets the selected resource, does nothing if there is no valid item * @param row row of the item * @param column column of the item */ void setCurrentItem(int row, int column); void showButtons(bool show); void addCustomButton(QAbstractButton *button, int cell); /// determines whether the preview right or below the splitter void setPreviewOrientation(Qt::Orientation orientation); /// determines whether the preview should tile the resource's image or not void setPreviewTiled(bool tiled); /// shows the preview converted to grayscale void setGrayscalePreview(bool grayscale); /// sets the visibility of tagging KlineEdits. void showTaggingBar(bool show); ///Set a proxy model with will be used to filter the resources void setProxyModel(QAbstractProxyModel *proxyModel); QSize viewSize() const; KoResourceItemView *itemView() const; void setViewModeButtonVisible(bool visible); QToolButton *viewModeButton() const; void setSynced(bool sync); bool eventFilter(QObject *object, QEvent *event) override; Q_SIGNALS: /// Emitted when a resource was selected - void resourceSelected(KoResource *resource); + void resourceSelected(KoResourceSP resource); /// Emitted when an *already selected* resource is clicked /// again - void resourceClicked(KoResource *resource); + void resourceClicked(KoResourceSP resource); void splitterMoved(); public Q_SLOTS: void slotButtonClicked(int button); void slotScrollerStateChanged(QScroller::State state){ KisKineticScroller::updateCursor(this, state); } private Q_SLOTS: void activated(const QModelIndex &index); void clicked(const QModelIndex &index); void contextMenuRequested(const QPoint &pos); void baseLengthChanged(int length); void updateView(); - void slotBeforeResourcesLayoutReset(KoResource *activateAfterReset); + void slotBeforeResourcesLayoutReset(KoResourceSP activateAfterReset); void slotAfterResourcesLayoutReset(); protected: void showEvent(QShowEvent *event) override; private: void updateButtonState(); - void updatePreview(KoResource *resource); + void updatePreview(KoResourceSP resource); void resizeEvent(QResizeEvent *event) override; /// Resource for a given model index /// @returns the resource pointer, 0 is index not valid - KoResource *resourceFromModelIndex(const QModelIndex &index) const; + KoResourceSP resourceFromModelIndex(const QModelIndex &index) const; class Private; Private *const d; QPushButton *importButton; QPushButton *deleteButton; }; #endif // KO_RESOURCE_ITEM_CHOOSER diff --git a/libs/widgets/KoResourceItemChooserContextMenu.cpp b/libs/widgets/KoResourceItemChooserContextMenu.cpp index 3ec8d2b7e5..d745482d90 100644 --- a/libs/widgets/KoResourceItemChooserContextMenu.cpp +++ b/libs/widgets/KoResourceItemChooserContextMenu.cpp @@ -1,216 +1,216 @@ /* This file is part of the KDE project * Copyright (c) 2013 Sascha Suelzer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * */ #include "KoResourceItemChooserContextMenu.h" #include #include #include #include #include #include KoLineEditAction::KoLineEditAction(QObject* parent) : QWidgetAction(parent) , m_closeParentOnTrigger(false) { QWidget* pWidget = new QWidget (0); QHBoxLayout* pLayout = new QHBoxLayout(); m_label = new QLabel(0); m_editBox = new QLineEdit(0); m_editBox->setClearButtonEnabled(true); m_AddButton = new QPushButton(); m_AddButton->setIcon(koIcon("list-add")); pLayout->addWidget(m_label); pLayout->addWidget(m_editBox); pLayout->addWidget(m_AddButton); pWidget->setLayout(pLayout); setDefaultWidget(pWidget); connect (m_editBox, &QLineEdit::returnPressed, this, &KoLineEditAction::onTriggered); connect (m_AddButton, &QPushButton::clicked, this, &KoLineEditAction::onTriggered); } KoLineEditAction::~KoLineEditAction() { } void KoLineEditAction::setIcon(const QIcon &icon) { QPixmap pixmap = QPixmap(icon.pixmap(16,16)); m_label->setPixmap(pixmap); } void KoLineEditAction::closeParentOnTrigger(bool closeParent) { m_closeParentOnTrigger = closeParent; } bool KoLineEditAction::closeParentOnTrigger() { return m_closeParentOnTrigger; } void KoLineEditAction::onTriggered() { if (! m_editBox->text().isEmpty()) { emit triggered( m_editBox->text()); m_editBox->text().clear(); if (m_closeParentOnTrigger) { this->parentWidget()->close(); m_editBox->clearFocus(); } } } void KoLineEditAction::setPlaceholderText(const QString& clickMessage) { m_editBox->setPlaceholderText(clickMessage); } void KoLineEditAction::setText(const QString& text) { m_editBox->setText(text); } void KoLineEditAction::setVisible(bool showAction) { QLayout* currentLayout = defaultWidget()->layout(); this->QAction::setVisible(showAction); for(int i=0;icount();i++) { currentLayout->itemAt(i)->widget()->setVisible(showAction); } defaultWidget()->setVisible(showAction); } -ContextMenuExistingTagAction::ContextMenuExistingTagAction(KoResource* resource, QString tag, QObject* parent) +ContextMenuExistingTagAction::ContextMenuExistingTagAction(KoResourceSP resource, QString tag, QObject* parent) : QAction(parent) , m_resource(resource) , m_tag(tag) { setText(tag); connect (this, SIGNAL(triggered()), this, SLOT(onTriggered())); } ContextMenuExistingTagAction::~ContextMenuExistingTagAction() { } void ContextMenuExistingTagAction::onTriggered() { emit triggered(m_resource, m_tag); } NewTagAction::~NewTagAction() { } -NewTagAction::NewTagAction(KoResource* resource, QMenu* parent) +NewTagAction::NewTagAction(KoResourceSP resource, QMenu* parent) :KoLineEditAction (parent) { m_resource = resource; setIcon(koIcon("document-new")); setPlaceholderText(i18n("New tag")); closeParentOnTrigger(true); connect (this, SIGNAL(triggered(QString)), this, SLOT(onTriggered(QString))); } void NewTagAction::onTriggered(const QString & tagName) { emit triggered(m_resource,tagName); } -KoResourceItemChooserContextMenu::KoResourceItemChooserContextMenu(KoResource* resource, +KoResourceItemChooserContextMenu::KoResourceItemChooserContextMenu(KoResourceSP resource, const QStringList& resourceTags, const QString& currentlySelectedTag, const QStringList& allTags) { QImage image = resource->image(); QIcon icon(QPixmap::fromImage(image)); QAction * label = new QAction(resource->name(), this); label->setIcon(icon); addAction(label); QMenu * removableTagsMenu; QMenu * assignableTagsMenu; QStringList removables = resourceTags; QStringList assignables = allTags; removables.sort(); assignables.sort(); assignableTagsMenu = addMenu(koIcon("list-add"),i18n("Assign to tag")); if (!removables.isEmpty()) { addSeparator(); QString currentTag = currentlySelectedTag; if (removables.contains(currentTag)) { assignables.removeAll(currentTag); removables.removeAll(currentTag); ContextMenuExistingTagAction * removeTagAction = new ContextMenuExistingTagAction(resource, currentTag, this); removeTagAction->setText(i18n("Remove from this tag")); removeTagAction->setIcon(koIcon("list-remove")); - connect(removeTagAction, SIGNAL(triggered(KoResource*,QString)), - this, SIGNAL(resourceTagRemovalRequested(KoResource*,QString))); + connect(removeTagAction, SIGNAL(triggered(KoResourceSP,QString)), + this, SIGNAL(resourceTagRemovalRequested(KoResourceSP,QString))); addAction(removeTagAction); } if (!removables.isEmpty()) { removableTagsMenu = addMenu(koIcon("list-remove"),i18n("Remove from other tag")); foreach (const QString &tag, removables) { assignables.removeAll(tag); ContextMenuExistingTagAction * removeTagAction = new ContextMenuExistingTagAction(resource, tag, this); - connect(removeTagAction, SIGNAL(triggered(KoResource*,QString)), - this, SIGNAL(resourceTagRemovalRequested(KoResource*,QString))); + connect(removeTagAction, SIGNAL(triggered(KoResourceSP,QString)), + this, SIGNAL(resourceTagRemovalRequested(KoResourceSP,QString))); removableTagsMenu->addAction(removeTagAction); } } } foreach (const QString &tag, assignables) { ContextMenuExistingTagAction * addTagAction = new ContextMenuExistingTagAction(resource, tag, this); - connect(addTagAction, SIGNAL(triggered(KoResource*,QString)), - this, SIGNAL(resourceTagAdditionRequested(KoResource*,QString))); + connect(addTagAction, SIGNAL(triggered(KoResourceSP,QString)), + this, SIGNAL(resourceTagAdditionRequested(KoResourceSP,QString))); assignableTagsMenu->addAction(addTagAction); } assignableTagsMenu->addSeparator(); NewTagAction * addTagAction = new NewTagAction(resource, this); - connect(addTagAction, SIGNAL(triggered(KoResource*,QString)), - this, SIGNAL(resourceAssignmentToNewTagRequested(KoResource*,QString))); + connect(addTagAction, SIGNAL(triggered(KoResourceSP,QString)), + this, SIGNAL(resourceAssignmentToNewTagRequested(KoResourceSP,QString))); assignableTagsMenu->addAction(addTagAction); } KoResourceItemChooserContextMenu::~KoResourceItemChooserContextMenu() { } diff --git a/libs/widgets/KoResourceItemChooserContextMenu.h b/libs/widgets/KoResourceItemChooserContextMenu.h index fc58380c6b..839548741f 100644 --- a/libs/widgets/KoResourceItemChooserContextMenu.h +++ b/libs/widgets/KoResourceItemChooserContextMenu.h @@ -1,121 +1,120 @@ /* * This file is part of the KDE project * Copyright (c) 2013 Sascha Suelzer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * */ #ifndef KORESOURCEITEMCHOOSERCONTEXTMENU_H #define KORESOURCEITEMCHOOSERCONTEXTMENU_H #include #include #include #include #include -class KoResource; - +#include class ContextMenuExistingTagAction : public QAction { Q_OBJECT public: - explicit ContextMenuExistingTagAction( KoResource * resource, QString tag, QObject* parent = 0); + explicit ContextMenuExistingTagAction( KoResourceSP resource, QString tag, QObject* parent = 0); ~ContextMenuExistingTagAction() override; Q_SIGNALS: - void triggered(KoResource * resource, QString tag); + void triggered(KoResourceSP resource, QString tag); protected Q_SLOTS: void onTriggered(); private: - KoResource * m_resource; + KoResourceSP m_resource; QString m_tag; }; /*! * A line edit QWidgetAction. * Default behavior: Closes its parent upon triggering. */ class KoLineEditAction : public QWidgetAction { Q_OBJECT public: explicit KoLineEditAction(QObject* parent); ~KoLineEditAction() override; void setIcon(const QIcon &icon); void closeParentOnTrigger(bool closeParent); bool closeParentOnTrigger(); void setPlaceholderText(const QString& clickMessage); void setText(const QString& text); void setVisible(bool showAction); Q_SIGNALS: void triggered(const QString &tag); protected Q_SLOTS: void onTriggered(); private: bool m_closeParentOnTrigger; QLabel * m_label; QLineEdit * m_editBox; QPushButton * m_AddButton; }; class NewTagAction : public KoLineEditAction { Q_OBJECT public: - explicit NewTagAction (KoResource* resource, QMenu* parent); + explicit NewTagAction (KoResourceSP resource, QMenu* parent); ~NewTagAction() override; Q_SIGNALS: - void triggered(KoResource * resource, const QString &tag); + void triggered(KoResourceSP resource, const QString &tag); protected Q_SLOTS: void onTriggered(const QString& tagName); private: - KoResource * m_resource; + KoResourceSP m_resource; }; class KoResourceItemChooserContextMenu : public QMenu { Q_OBJECT public: explicit KoResourceItemChooserContextMenu ( - KoResource* resource, + KoResourceSP resource, const QStringList& resourceTags, const QString& currentlySelectedTag, const QStringList& allTags ); ~KoResourceItemChooserContextMenu() override; Q_SIGNALS: /// Emitted when a resource should be added to an existing tag. - void resourceTagAdditionRequested(KoResource* resource, const QString& tag); + void resourceTagAdditionRequested(KoResourceSP resource, const QString& tag); /// Emitted when a resource should be removed from an existing tag. - void resourceTagRemovalRequested(KoResource* resource, const QString& tag); + void resourceTagRemovalRequested(KoResourceSP resource, const QString& tag); /// Emitted when a resource should be added to a new tag, which will need to be created. - void resourceAssignmentToNewTagRequested(KoResource* resource, const QString& tag); + void resourceAssignmentToNewTagRequested(KoResourceSP resource, const QString& tag); }; #endif // KORESOURCEITEMCHOOSERCONTEXTMENU_H diff --git a/libs/widgets/KoResourceItemDelegate.cpp b/libs/widgets/KoResourceItemDelegate.cpp index 1bb43a466a..851533249c 100644 --- a/libs/widgets/KoResourceItemDelegate.cpp +++ b/libs/widgets/KoResourceItemDelegate.cpp @@ -1,87 +1,87 @@ /* This file is part of the KDE project * Copyright (C) 2008 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoResourceItemDelegate.h" #include #include KoResourceItemDelegate::KoResourceItemDelegate( QObject * parent ) : QAbstractItemDelegate( parent ), m_checkerPainter( 4 ) { } -void KoResourceItemDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const +void KoResourceItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem & option, const QModelIndex &index) const { if( ! index.isValid() ) return; - KoResource * resource = static_cast( index.internalPointer() ); + KoResourceSP resource = KoResourceSP(static_cast( index.internalPointer())); if (!resource) return; painter->save(); if (option.state & QStyle::State_Selected) painter->fillRect( option.rect, option.palette.highlight() ); QRect innerRect = option.rect.adjusted( 2, 1, -2, -1 ); - KoAbstractGradient * gradient = dynamic_cast( resource ); + KoAbstractGradientSP gradient = resource.dynamicCast(); if (gradient) { QGradient * g = gradient->toQGradient(); QLinearGradient paintGradient; paintGradient.setStops( g->stops() ); paintGradient.setStart( innerRect.topLeft() ); paintGradient.setFinalStop( innerRect.topRight() ); m_checkerPainter.paint( *painter, innerRect ); painter->fillRect( innerRect, QBrush( paintGradient ) ); delete g; } else { QImage thumbnail = index.data( Qt::DecorationRole ).value(); QSize imageSize = thumbnail.size(); if(imageSize.height() > innerRect.height() || imageSize.width() > innerRect.width()) { qreal scaleW = static_cast( innerRect.width() ) / static_cast( imageSize.width() ); qreal scaleH = static_cast( innerRect.height() ) / static_cast( imageSize.height() ); qreal scale = qMin( scaleW, scaleH ); int thumbW = static_cast( imageSize.width() * scale ); int thumbH = static_cast( imageSize.height() * scale ); thumbnail = thumbnail.scaled( thumbW, thumbH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); } painter->setRenderHint(QPainter::SmoothPixmapTransform, true); if (thumbnail.hasAlphaChannel()) { painter->fillRect(innerRect, Qt::white); // no checkers, they are confusing with patterns. } painter->fillRect( innerRect, QBrush(thumbnail) ); } painter->restore(); } QSize KoResourceItemDelegate::sizeHint( const QStyleOptionViewItem & optionItem, const QModelIndex & ) const { return optionItem.decorationSize; } diff --git a/libs/widgets/KoResourcePopupAction.cpp b/libs/widgets/KoResourcePopupAction.cpp index ea9d1710bb..08805d7e1d 100644 --- a/libs/widgets/KoResourcePopupAction.cpp +++ b/libs/widgets/KoResourcePopupAction.cpp @@ -1,210 +1,210 @@ /* This file is part of the KDE project * Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) * Copyright (C) 2012 Jean-Nicolas Artaud * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoResourcePopupAction.h" #include "KoResourceServerAdapter.h" #include "KoResourceItemView.h" #include "KoLegacyResourceModel.h" #include "KoResourceItemDelegate.h" #include #include "KoCheckerBoardPainter.h" #include "KoShapeBackground.h" #include #include #include #include #include #include #include #include #include #include #include #include #include class KoResourcePopupAction::Private { public: QMenu *menu = 0; KoLegacyResourceModel *model = 0; KoResourceItemView *resourceList = 0; QSharedPointer background; KoImageCollection *imageCollection = 0; KoCheckerBoardPainter checkerPainter {4}; }; KoResourcePopupAction::KoResourcePopupAction(QSharedPointerresourceAdapter, QObject *parent) : QAction(parent) , d(new Private()) { Q_ASSERT(resourceAdapter); d->menu = new QMenu(); QWidget *widget = new QWidget(); QWidgetAction *wdgAction = new QWidgetAction(this); d->resourceList = new KoResourceItemView(widget); d->model = new KoLegacyResourceModel(resourceAdapter, widget); d->resourceList->setModel(d->model); d->resourceList->setItemDelegate(new KoResourceItemDelegate(widget)); KoLegacyResourceModel * resourceModel = qobject_cast(d->resourceList->model()); if (resourceModel) { resourceModel->setColumnCount(1); } - KoResource *resource = 0; - QList resources = resourceAdapter->resources(); + KoResourceSP resource = 0; + QList resources = resourceAdapter->resources(); if (resources.count() > 0) { resource = resources.at(0); d->resourceList->setCurrentIndex(d->model->indexFromResource(resource)); indexChanged(d->resourceList->currentIndex()); } QHBoxLayout *layout = new QHBoxLayout(widget); layout->addWidget(d->resourceList); widget->setLayout(layout); wdgAction->setDefaultWidget(widget); d->menu->addAction(wdgAction); setMenu(d->menu); new QHBoxLayout(d->menu); d->menu->layout()->addWidget(widget); d->menu->layout()->setMargin(0); connect(d->resourceList, SIGNAL(clicked(QModelIndex)), this, SLOT(indexChanged(QModelIndex))); updateIcon(); } KoResourcePopupAction::~KoResourcePopupAction() { /* Removing the actions here make them be deleted together with their default widget. * This happens only if the actions are QWidgetAction, and we know they are since * the only ones added are in KoResourcePopupAction constructor. */ int i = 0; while(d->menu->actions().size() > 0) { d->menu->removeAction(d->menu->actions()[i]); ++i; } delete d->menu; delete d->imageCollection; delete d; } QSharedPointer KoResourcePopupAction::currentBackground() const { return d->background; } void KoResourcePopupAction::setCurrentBackground(QSharedPointer background) { d->background = background; updateIcon(); } -void KoResourcePopupAction::setCurrentResource(KoResource *resource) +void KoResourcePopupAction::setCurrentResource(KoResourceSP resource) { QModelIndex index = d->model->indexFromResource(resource); if (index.isValid()) { d->resourceList->setCurrentIndex(index); indexChanged(index); } } -KoResource* KoResourcePopupAction::currentResource() const +KoResourceSP KoResourcePopupAction::currentResource() const { QModelIndex index = d->resourceList->currentIndex(); if (!index.isValid()) return 0; - return static_cast(index.internalPointer()); + return QSharedPointer(static_cast(index.internalPointer())); } void KoResourcePopupAction::indexChanged(const QModelIndex &modelIndex) { if (! modelIndex.isValid()) { return; } d->menu->hide(); - KoResource *resource = static_cast(modelIndex.internalPointer()); + KoResourceSP resource = QSharedPointer(static_cast(modelIndex.internalPointer())); if(resource) { - KoAbstractGradient *gradient = dynamic_cast(resource); - KoPattern *pattern = dynamic_cast(resource); + KoAbstractGradientSP gradient = resource.dynamicCast(); + KoPatternSP pattern = resource.dynamicCast(); if (gradient) { QGradient *qg = gradient->toQGradient(); qg->setCoordinateMode(QGradient::ObjectBoundingMode); d->background = QSharedPointer(new KoGradientBackground(qg)); } else if (pattern) { KoImageCollection *collection = new KoImageCollection(); d->background = QSharedPointer(new KoPatternBackground(collection)); qSharedPointerDynamicCast(d->background)->setPattern(pattern->pattern()); } emit resourceSelected(d->background); updateIcon(); } } void KoResourcePopupAction::updateIcon() { QSize iconSize; QToolButton *toolButton = dynamic_cast(parentWidget()); if (toolButton) { iconSize = QSize(toolButton->iconSize()); } else { iconSize = QSize(16, 16); } // This must be a QImage, as drawing to a QPixmap outside the // UI thread will cause sporadic crashes. QImage pm = QImage(iconSize, QImage::Format_ARGB32_Premultiplied); pm.fill(Qt::transparent); QPainter p(&pm); QSharedPointer gradientBackground = qSharedPointerDynamicCast(d->background); QSharedPointer patternBackground = qSharedPointerDynamicCast(d->background); if (gradientBackground) { QRect innerRect(0, 0, iconSize.width(), iconSize.height()); QLinearGradient paintGradient; paintGradient.setStops(gradientBackground->gradient()->stops()); paintGradient.setStart(innerRect.topLeft()); paintGradient.setFinalStop(innerRect.topRight()); d->checkerPainter.paint(p, innerRect); p.fillRect(innerRect, QBrush(paintGradient)); } else if (patternBackground) { d->checkerPainter.paint(p, QRect(QPoint(),iconSize)); p.fillRect(0, 0, iconSize.width(), iconSize.height(), patternBackground->pattern()); } p.end(); setIcon(QIcon(QPixmap::fromImage(pm))); } diff --git a/libs/widgets/KoResourcePopupAction.h b/libs/widgets/KoResourcePopupAction.h index baa1054bee..884e7d59f0 100644 --- a/libs/widgets/KoResourcePopupAction.h +++ b/libs/widgets/KoResourcePopupAction.h @@ -1,73 +1,74 @@ /* This file is part of the KDE project * Made by Tomislav Lukman (tomislav.lukman@ck.tel.hr) * Copyright (C) 2012 Jean-Nicolas Artaud * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KORESOURCEPOPUPACTION_H #define KORESOURCEPOPUPACTION_H #include #include -#include "kritawidgets_export.h" +#include class KoShapeBackground; class KoAbstractResourceServerAdapter; class QModelIndex; -class KoResource; + +#include "kritawidgets_export.h" class KRITAWIDGETS_EXPORT KoResourcePopupAction : public QAction { Q_OBJECT public: /** * Constructs a KoResourcePopupAction (gradient or pattern) with the specified parent. * * @param parent The parent for this action. */ explicit KoResourcePopupAction(QSharedPointergradientResourceAdapter, QObject *parent = 0); /** * Destructor */ ~KoResourcePopupAction() override; QSharedPointer currentBackground() const; void setCurrentBackground(QSharedPointer background); - void setCurrentResource(KoResource *resource); - KoResource *currentResource() const; + void setCurrentResource(KoResourceSP resource); + KoResourceSP currentResource() const; Q_SIGNALS: /// Emitted when a resource was selected void resourceSelected(QSharedPointer background); public Q_SLOTS: void updateIcon(); private Q_SLOTS: void indexChanged(const QModelIndex &modelIndex); private: class Private; Private * const d; }; #endif /* KORESOURCEPOPUPACTION_H */ diff --git a/libs/widgets/KoResourceSelector.cpp b/libs/widgets/KoResourceSelector.cpp index eb139c7398..a791cfa875 100644 --- a/libs/widgets/KoResourceSelector.cpp +++ b/libs/widgets/KoResourceSelector.cpp @@ -1,213 +1,214 @@ /* This file is part of the KDE project * Copyright (C) 2008 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoResourceSelector.h" #include #include #include #include #include #include #include #include #include #include #include class Q_DECL_HIDDEN KoResourceSelector::Private { public: Private() : displayMode(ImageMode) {} DisplayMode displayMode; void updateIndex( KoResourceSelector * me ) { KoLegacyResourceModel * resourceModel = qobject_cast(me->model()); if (!resourceModel) return; if (!resourceModel->rowCount()) return; int currentIndex = me->currentIndex(); QModelIndex currentModelIndex = me->view()->currentIndex(); if (currentIndex < 0 || !currentModelIndex.isValid()) { me->blockSignals(true); me->view()->setCurrentIndex( resourceModel->index( 0, 0 ) ); me->setCurrentIndex(0); me->blockSignals(false); me->update(); } } }; KoResourceSelector::KoResourceSelector(QWidget * parent) : QComboBox( parent ), d( new Private() ) { connect( this, SIGNAL(currentIndexChanged(int)), this, SLOT(indexChanged(int)) ); setMouseTracking(true); } KoResourceSelector::KoResourceSelector( QSharedPointer resourceAdapter, QWidget * parent ) : QComboBox( parent ), d( new Private() ) { Q_ASSERT(resourceAdapter); setView( new KoResourceItemView(this) ); setModel( new KoLegacyResourceModel(resourceAdapter, this) ); setItemDelegate( new KoResourceItemDelegate( this ) ); setMouseTracking(true); d->updateIndex(this); connect( this, SIGNAL(currentIndexChanged(int)), this, SLOT(indexChanged(int)) ); - connect(resourceAdapter.data(), SIGNAL(resourceAdded(KoResource*)), - this, SLOT(resourceAdded(KoResource*))); - connect(resourceAdapter.data(), SIGNAL(removingResource(KoResource*)), - this, SLOT(resourceRemoved(KoResource*))); + connect(resourceAdapter.data(), SIGNAL(resourceAdded(KoResourceSP )), + this, SLOT(resourceAdded(KoResourceSP ))); + connect(resourceAdapter.data(), SIGNAL(removingResource(KoResourceSP )), + this, SLOT(resourceRemoved(KoResourceSP ))); } KoResourceSelector::~KoResourceSelector() { delete d; } void KoResourceSelector::paintEvent( QPaintEvent *pe ) { QComboBox::paintEvent( pe ); if (d->displayMode == ImageMode) { QStyleOptionComboBox option; option.initFrom( this ); QRect r = style()->subControlRect( QStyle::CC_ComboBox, &option, QStyle::SC_ComboBoxEditField, this ); QStyleOptionViewItem viewOption; viewOption.initFrom( this ); viewOption.rect = r; QPainter painter( this ); itemDelegate()->paint( &painter, viewOption, view()->currentIndex() ); } } void KoResourceSelector::mousePressEvent( QMouseEvent * event ) { QStyleOptionComboBox opt; opt.initFrom( this ); opt.subControls = QStyle::SC_All; opt.activeSubControls = QStyle::SC_ComboBoxArrow; QStyle::SubControl sc = style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt, mapFromGlobal(event->globalPos()), this); // only clicking on combobox arrow shows popup, // otherwise the resourceApplied signal is send with the current resource if (sc == QStyle::SC_ComboBoxArrow) QComboBox::mousePressEvent( event ); else { QModelIndex index = view()->currentIndex(); if( ! index.isValid() ) return; - KoResource * resource = static_cast( index.internalPointer() ); + KoResourceSP resource = KoResourceSP(static_cast(index.internalPointer())); if( resource ) emit resourceApplied( resource ); } } void KoResourceSelector::mouseMoveEvent( QMouseEvent * event ) { QStyleOptionComboBox option; option.initFrom( this ); QRect r = style()->subControlRect( QStyle::CC_ComboBox, &option, QStyle::SC_ComboBoxEditField, this ); if (r.contains(event->pos())) setCursor(Qt::PointingHandCursor); else unsetCursor(); } void KoResourceSelector::setResourceAdapter(QSharedPointerresourceAdapter) { Q_ASSERT(resourceAdapter); setModel(new KoLegacyResourceModel(resourceAdapter, this)); d->updateIndex(this); - connect(resourceAdapter.data(), SIGNAL(resourceAdded(KoResource*)), - this, SLOT(resourceAdded(KoResource*))); - connect(resourceAdapter.data(), SIGNAL(removingResource(KoResource*)), - this, SLOT(resourceRemoved(KoResource*))); + connect(resourceAdapter.data(), SIGNAL(resourceAdded(KoResourceSP )), + this, SLOT(resourceAdded(KoResourceSP ))); + connect(resourceAdapter.data(), SIGNAL(removingResource(KoResourceSP )), + this, SLOT(resourceRemoved(KoResourceSP ))); } void KoResourceSelector::setDisplayMode(DisplayMode mode) { if (mode == d->displayMode) return; switch(mode) { case ImageMode: setItemDelegate(new KoResourceItemDelegate(this)); setView( new KoResourceItemView(this) ); break; case TextMode: setItemDelegate(new QStyledItemDelegate(this)); setView(new QListView(this)); break; } d->displayMode = mode; d->updateIndex(this); } void KoResourceSelector::setColumnCount( int columnCount ) { KoLegacyResourceModel * resourceModel = qobject_cast(model()); if (resourceModel) resourceModel->setColumnCount( columnCount ); } void KoResourceSelector::setRowHeight( int rowHeight ) { QTableView * tableView = qobject_cast(view()); if (tableView) tableView->verticalHeader()->setDefaultSectionSize( rowHeight ); } void KoResourceSelector::indexChanged( int ) { QModelIndex index = view()->currentIndex(); - if( ! index.isValid() ) + if(!index.isValid()) { return; - - KoResource * resource = static_cast( index.internalPointer() ); - if( resource ) + } + KoResourceSP resource = KoResourceSP(static_cast(index.internalPointer())); + if (resource) { emit resourceSelected( resource ); + } } -void KoResourceSelector::resourceAdded(KoResource*) +void KoResourceSelector::resourceAdded(KoResourceSP ) { d->updateIndex(this); } -void KoResourceSelector::resourceRemoved(KoResource*) +void KoResourceSelector::resourceRemoved(KoResourceSP ) { d->updateIndex(this); } diff --git a/libs/widgets/KoResourceSelector.h b/libs/widgets/KoResourceSelector.h index 64d5c83ce3..c30bb1c7a9 100644 --- a/libs/widgets/KoResourceSelector.h +++ b/libs/widgets/KoResourceSelector.h @@ -1,94 +1,93 @@ /* This file is part of the KDE project * Copyright (C) 2008 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KORESOURCESELECTOR_H #define KORESOURCESELECTOR_H #include "kritawidgets_export.h" #include - +#include class QMouseEvent; class KoAbstractResourceServerAdapter; -class KoResource; /** * A custom combobox widget for selecting resource items like gradients or patterns. */ class KRITAWIDGETS_EXPORT KoResourceSelector : public QComboBox { Q_OBJECT public: enum DisplayMode { ImageMode, ///< Displays image of resources (default) TextMode ///< Displays name of resources }; /** * Constructs a new resource selector. * @param parent the parent widget */ explicit KoResourceSelector(QWidget *parent = 0); /** * Constructs a new resource selector showing the resources of the given resource adapter. * @param resourceAdapter the resource adapter providing the resources to display * @param parent the parent widget */ explicit KoResourceSelector( QSharedPointer resourceAdapter, QWidget * parent = 0 ); /// Destroys the resource selector ~KoResourceSelector() override; /// Sets the resource adaptor to get resources from void setResourceAdapter(QSharedPointerresourceAdapter); /// Sets the display mode void setDisplayMode(DisplayMode mode); /// Sets number of columns to display in the popup view void setColumnCount( int columnCount ); /// Sets the height of the popup view rows void setRowHeight( int rowHeight ); Q_SIGNALS: /// Emitted when a resource was selected - void resourceSelected( KoResource * resource ); + void resourceSelected( KoResourceSP resource ); /// Is emitted when the user has clicked on the current resource - void resourceApplied( KoResource * resource ); + void resourceApplied( KoResourceSP resource ); protected: /// reimplemented void paintEvent( QPaintEvent * ) override; /// reimplemented void mousePressEvent( QMouseEvent * ) override; /// reimplemented void mouseMoveEvent( QMouseEvent * event ) override; private Q_SLOTS: void indexChanged( int index ); - void resourceAdded(KoResource*); - void resourceRemoved(KoResource*); + void resourceAdded(KoResourceSP ); + void resourceRemoved(KoResourceSP ); private: class Private; Private * const d; }; #endif // KORESOURCESELECTOR_H diff --git a/libs/widgets/KoResourceServer.h b/libs/widgets/KoResourceServer.h index 28b6c1bcac..ad03fd40dd 100644 --- a/libs/widgets/KoResourceServer.h +++ b/libs/widgets/KoResourceServer.h @@ -1,707 +1,675 @@ /* 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) 2007 Jan Hambrecht Copyright (C) 2011 Srikanth Tiyyagura Copyright (c) 2013 Sascha Suelzer 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 KORESOURCESERVER_H #define KORESOURCESERVER_H #include #include #include #include #include #include #include #include #include "KoResource.h" -#include "KoResourceServerPolicies.h" #include "KoResourceServerObserver.h" #include "KoResourceTagStore.h" #include "KoResourcePaths.h" #include #include #include #include "kritawidgets_export.h" #include "WidgetsDebug.h" class KoResource; /** * KoResourceServerBase is the base class of all resource servers */ class KRITAWIDGETS_EXPORT KoResourceServerBase { public: /** * Constructs a KoResourceServerBase * @param resource type, has to be the same as used by KoResourcePaths * @param extensions the file extensions separate by ':', e.g. "*.kgr:*.svg:*.ggr" */ KoResourceServerBase(const QString& type, const QString& extensions) : m_resourceModel(type) , m_type(type) , m_extensions(extensions) { qDebug() << "Creating KoResourceServerBase" << m_type << m_extensions; } virtual ~KoResourceServerBase() {} virtual int resourceCount() const = 0; virtual void loadResources(QStringList filenames) = 0; virtual QStringList blackListedFiles() = 0; virtual QStringList queryResources(const QString &query) const = 0; QString type() const { return m_type; } /** * File extensions for resources of the server * @returns the file extensions separated by ':', e.g. "*.kgr:*.svg:*.ggr" */ QString extensions() const { return m_extensions; } QStringList fileNames() { QStringList extensionList = m_extensions.split(':'); QStringList fileNames; foreach (const QString &extension, extensionList) { fileNames += KoResourcePaths::findAllResources(type().toLatin1(), extension, KoResourcePaths::Recursive); } return fileNames; } protected: KisResourceModel m_resourceModel; QStringList m_blackListFileNames; friend class KoResourceTagStore; - virtual KoResource *byMd5(const QByteArray &md5) const = 0; - virtual KoResource *byFileName(const QString &fileName) const = 0; + virtual KoResourceSP byMd5(const QByteArray &md5) const = 0; + virtual KoResourceSP byFileName(const QString &fileName) const = 0; private: QString m_type; QString m_extensions; protected: QMutex m_loadLock; }; /** * KoResourceServer manages the resources of one type. It stores, * loads and saves the resources. To keep track of changes the server * can be observed with a KoResourceServerObserver - * - * The \p Policy template parameter defines the way how the lifetime - - * of a resource is handled. There are to predefined policies: - - * - * o PointerStoragePolicy --- usual pointers with ownership over - * the resource. - - * o SharedPointerStoragePolicy --- shared pointers. The server does no - * extra handling for the lifetime of - * the resource. - * - * Use the former for usual resources and the latter for shared pointer based - * ones. */ -template > +template class KoResourceServer : public KoResourceServerBase { public: - typedef typename Policy::PointerType PointerType; - typedef KoResourceServerObserver ObserverType; + typedef KoResourceServerObserver ObserverType; + KoResourceServer(const QString& type, const QString& extensions) : KoResourceServerBase(type, extensions) { m_blackListFile = KoResourcePaths::locateLocal("data", type + ".blacklist"); m_blackListFileNames = readBlackListFile(); m_tagStore = new KoResourceTagStore(this); } ~KoResourceServer() override { if (m_tagStore) { delete m_tagStore; } Q_FOREACH (ObserverType* observer, m_observers) { observer->unsetResourceServer(); } - - Q_FOREACH (PointerType res, m_resources) { - Policy::deleteResource(res); - } - m_resources.clear(); - } int resourceCount() const override { return m_resourceModel.rowCount(); } /** * Loads a set of resources and adds them to the resource server. * If a filename appears twice the resource will only be added once. Resources that can't * be loaded or and invalid aren't added to the server. * @param filenames list of filenames to be loaded */ - void loadResources(QStringList filenames) override { + void loadResources(QStringList /*filenames*/) override { } void loadTags() { m_tagStore->loadTags(); } void clearOldSystemTags() { m_tagStore->clearOldSystemTags(); } /// Adds an already loaded resource to the server - bool addResource(PointerType resource, bool save = true, bool infront = false) { + bool addResource(QSharedPointer resource, bool save = true, bool infront = false) { if (!resource->valid()) { warnWidgets << "Tried to add an invalid resource!"; return false; } if (save) { QFileInfo fileInfo(resource->filename()); QDir d(fileInfo.path()); if (!d.exists()) { d.mkdir(fileInfo.path()); } if (fileInfo.exists()) { QString filename = fileInfo.path() + "/" + fileInfo.baseName() + "XXXXXX" + "." + fileInfo.suffix(); debugWidgets << "fileName is " << filename; QTemporaryFile file(filename); if (file.open()) { debugWidgets << "now " << file.fileName(); resource->setFilename(file.fileName()); } } if (!resource->save()) { warnWidgets << "Could not save resource!"; return false; } } Q_ASSERT(!resource->filename().isEmpty() || !resource->name().isEmpty()); if (resource->filename().isEmpty()) { resource->setFilename(resource->name()); } else if (resource->name().isEmpty()) { resource->setName(resource->filename()); } m_resourcesByFilename[resource->shortFilename()] = resource; addResourceToMd5Registry(resource); m_resourcesByName[resource->name()] = resource; if (infront) { m_resources.insert(0, resource); } else { m_resources.append(resource); } notifyResourceAdded(resource); return true; } /** * Removes a given resource from the blacklist. */ - bool removeFromBlacklist(PointerType resource) { + bool removeFromBlacklist(QSharedPointer resource) { if (m_blackListFileNames.contains(resource->filename())) { m_blackListFileNames.removeAll(resource->filename()); writeBlackListFile(); return true; } return false; } /// Remove a resource from Resource Server but not from a file - bool removeResourceFromServer(PointerType resource){ + bool removeResourceFromServer(QSharedPointer resource){ if ( !m_resourcesByFilename.contains( resource->shortFilename() ) ) { return false; } removeResourceFromMd5Registry(resource); m_resourcesByName.remove(resource->name()); m_resourcesByFilename.remove(resource->shortFilename()); m_resources.removeAt(m_resources.indexOf(resource)); m_tagStore->removeResource(resource); notifyRemovingResource(resource); - Policy::deleteResource(resource); return true; } /// Remove a resource from the resourceserver and blacklist it - bool removeResourceAndBlacklist(PointerType resource) { + bool removeResourceAndBlacklist(QSharedPointer resource) { if ( !m_resourcesByFilename.contains( resource->shortFilename() ) ) { return false; } removeResourceFromMd5Registry(resource); m_resourcesByName.remove(resource->name()); m_resourcesByFilename.remove(resource->shortFilename()); m_resources.removeAt(m_resources.indexOf(resource)); m_tagStore->removeResource(resource); notifyRemovingResource(resource); m_blackListFileNames.append(resource->filename()); writeBlackListFile(); - Policy::deleteResource(resource); return true; } - QList resources() { - m_loadLock.lock(); - QList resourceList = m_resources; - Q_FOREACH (PointerType r, m_resourceBlackList) { - resourceList.removeOne(r); + QList> resources() { + QList> resourceList; + for (int row = 0; row < m_resourceModel.rowCount(); ++row) { + resourceList << m_resourceModel.resourceForIndex(m_resourceModel.index(row, 0)).dynamicCast(); } - m_loadLock.unlock(); return resourceList; } /// Returns path where to save user defined and imported resources to virtual QString saveLocation() { return KoResourcePaths::saveLocation(type().toLatin1()); } /** * Creates a new resource from a given file and adds them to the resource server * The base implementation does only load one resource per file, override to implement collections * @param filename file name of the resource file to be imported * @param fileCreation decides whether to create the file in the saveLocation() directory */ virtual bool importResourceFile(const QString & filename , bool fileCreation=true) { QFileInfo fi(filename); if (!fi.exists()) return false; if ( fi.size() == 0) return false; - PointerType resource = createResource( filename ); + QSharedPointer resource = createResource( filename ); resource->load(); if (!resource->valid()) { warnWidgets << "Import failed! Resource is not valid"; - Policy::deleteResource(resource); return false; } if (fileCreation) { Q_ASSERT(!resource->defaultFileExtension().isEmpty()); Q_ASSERT(!saveLocation().isEmpty()); QString newFilename = saveLocation() + fi.baseName() + resource->defaultFileExtension(); QFileInfo fileInfo(newFilename); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(saveLocation() + fi.baseName() + QString("%1").arg(i) + resource->defaultFileExtension()); i++; } resource->setFilename(fileInfo.filePath()); } - - - if(!addResource(resource)) { - Policy::deleteResource(resource); - } - return true; } /// Removes the resource file from the resource server void removeResourceFile(const QString & filename) { QFileInfo fi(filename); - PointerType resource = resourceByFilename(fi.fileName()); + QSharedPointer resource = resourceByFilename(fi.fileName()); if (!resource) { warnWidgets << "Resource file do not exist "; return; } removeResourceFromServer(resource); } /** * Addes an observer to the server * @param observer the observer to be added * @param notifyLoadedResources determines if the observer should be notified about the already loaded resources */ void addObserver(ObserverType* observer, bool notifyLoadedResources = true) { m_loadLock.lock(); if(observer && !m_observers.contains(observer)) { m_observers.append(observer); if(notifyLoadedResources) { - Q_FOREACH (PointerType resource, m_resourcesByFilename) { + Q_FOREACH (QSharedPointer resource, m_resourcesByFilename) { observer->resourceAdded(resource); } } } m_loadLock.unlock(); } /** * Removes an observer from the server * @param observer the observer to be removed */ void removeObserver(ObserverType* observer) { int index = m_observers.indexOf( observer ); if( index < 0 ) return; m_observers.removeAt( index ); } - PointerType resourceByFilename(const QString& filename) const + QSharedPointer resourceByFilename(const QString& /*filename*/) const { - if (m_resourcesByFilename.contains(filename)) { - return m_resourcesByFilename[filename]; - } +// if (m_resourcesByFilename.contains(filename)) { +// return m_resourcesByFilename[filename]; +// } return 0; } - PointerType resourceByName( const QString& name ) const + QSharedPointer resourceByName( const QString& /*name */) const { - if (m_resourcesByName.contains(name)) { - return m_resourcesByName[name]; - } +// if (m_resourcesByName.contains(name)) { +// return m_resourcesByName[name]; +// } return 0; } - PointerType resourceByMD5(const QByteArray& md5) const + QSharedPointer resourceByMD5(const QByteArray& /*md5*/) const { - return m_resourcesByMd5.value(md5); +// return m_resourcesByMd5.value(md5); + return 0; } /** * Call after changing the content of a resource; * Notifies the connected views. */ - void updateResource( PointerType resource ) + void updateResource(QSharedPointer resource) { notifyResourceChanged(resource); } QStringList blackListedFiles() override { if (type() == "kis_resourcebundles") { KConfigGroup group = KSharedConfig::openConfig()->group("BundleHack"); if (group.readEntry("HideKrita3Bundle", true)) { Q_FOREACH(const QString &filename, fileNames()) { if (filename.endsWith("Krita_3_Default_Resources.bundle")) { if (!m_blackListFileNames.contains(filename)) { m_blackListFileNames.append(filename); } } } } // qDebug() << "blacklisted filenames" << m_blackListFileNames; } return m_blackListFileNames; } void removeBlackListedFiles() { QStringList remainingFiles; // Files that can't be removed e.g. no rights will stay blacklisted Q_FOREACH (const QString &filename, m_blackListFileNames) { QFile file( filename ); if( ! file.remove() ) { remainingFiles.append(filename); } } m_blackListFileNames = remainingFiles; writeBlackListFile(); } QStringList tagNamesList() const { return m_tagStore->tagNamesList(); } // don't use these method directly since it doesn't update views! - void addTag( KoResource* resource,const QString& tag) + void addTag(KoResourceSP resource, const QString& tag) { - m_tagStore->addTag(resource,tag); + m_tagStore->addTag(resource, tag); } // don't use these method directly since it doesn't update views! - void delTag( KoResource* resource,const QString& tag) + void delTag(KoResourceSP resource, const QString& tag) { m_tagStore->delTag(resource, tag); } QStringList searchTag(const QString& lineEditText) { return m_tagStore->searchTag(lineEditText); } void tagCategoryAdded(const QString& tag) { m_tagStore->serializeTags(); Q_FOREACH (ObserverType* observer, m_observers) { observer->syncTagAddition(tag); } } void tagCategoryRemoved(const QString& tag) { m_tagStore->delTag(tag); m_tagStore->serializeTags(); Q_FOREACH (ObserverType* observer, m_observers) { observer->syncTagRemoval(tag); } } void tagCategoryMembersChanged() { m_tagStore->serializeTags(); Q_FOREACH (ObserverType* observer, m_observers) { observer->syncTaggedResourceView(); } } QStringList queryResources(const QString &query) const override { return m_tagStore->searchTag(query); } - QStringList assignedTagsList(KoResource* resource) const + QStringList assignedTagsList(KoResourceSP resource) const { return m_tagStore->assignedTagsList(resource); } /** * Create one or more resources from a single file. By default one resource is created. * Override to create more resources from the file. * @param filename the filename of the resource or resource collection */ - virtual QList createResources( const QString & filename ) + virtual QList> createResources( const QString & filename ) { - QList createdResources; + QList> createdResources; createdResources.append(createResource(filename)); return createdResources; } - virtual PointerType createResource( const QString & filename ) = 0; + virtual QSharedPointer createResource( const QString & filename ) = 0; /// Return the currently stored resources in alphabetical order, overwrite for customized sorting - virtual QList sortedResources() + virtual QList> sortedResources() { - QMap sortedNames; + QMap> sortedNames; Q_FOREACH (const QString &name, m_resourcesByName.keys()) { sortedNames.insert(name.toLower(), m_resourcesByName[name]); } return sortedNames.values(); } protected: - void notifyResourceAdded(PointerType resource) + void notifyResourceAdded(QSharedPointer resource) { Q_FOREACH (ObserverType* observer, m_observers) { observer->resourceAdded(resource); } } - void notifyRemovingResource(PointerType resource) + void notifyRemovingResource(QSharedPointer resource) { Q_FOREACH (ObserverType* observer, m_observers) { observer->removingResource(resource); } } - void notifyResourceChanged(PointerType resource) + void notifyResourceChanged(QSharedPointer resource) { Q_FOREACH (ObserverType* observer, m_observers) { observer->resourceChanged(resource); } } /// Reads the xml file and returns the filenames as a list QStringList readBlackListFile() { QStringList filenameList; QFile f(m_blackListFile); if (!f.open(QIODevice::ReadOnly)) { return filenameList; } QDomDocument doc; if (!doc.setContent(&f)) { warnWidgets << "The file could not be parsed."; return filenameList; } QDomElement root = doc.documentElement(); if (root.tagName() != "resourceFilesList") { warnWidgets << "The file doesn't seem to be of interest."; return filenameList; } QDomElement file = root.firstChildElement("file"); while (!file.isNull()) { QDomNode n = file.firstChild(); QDomElement e = n.toElement(); if (e.tagName() == "name") { // If the krita bundle has landed in the blacklist, skip it. if (type() == "kis_resourcebundles") { // qDebug() << "Checking for not reading bundle" << e.text(); if (e.text().endsWith("Krita_3_Default_Resources.bundle")) { file = file.nextSiblingElement("file"); } } filenameList.append(e.text().replace(QString("~"), QDir::homePath())); } file = file.nextSiblingElement("file"); } // if (type() == "kis_resourcebundles") { // qDebug() << "Read bundle blacklist" << filenameList; // } return filenameList; } /// write the blacklist file entries to an xml file void writeBlackListFile() { QFile f(m_blackListFile); if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { warnWidgets << "Cannot write meta information to '" << m_blackListFile << "'." << endl; return; } QDomDocument doc; QDomElement root; QDomDocument docTemp("m_blackListFile"); doc = docTemp; doc.appendChild(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"")); root = doc.createElement("resourceFilesList"); doc.appendChild(root); Q_FOREACH (QString filename, m_blackListFileNames) { // Don't write the krita3 bundle to the blacklist, since its location will change // when using the appimate. if (type() == "kis_resourcebundles") { // qDebug() << "Checking for Not writing krita 3 bundle" << filename; if (filename.endsWith("Krita_3_Default_Resources.bundle")) continue; } QDomElement fileEl = doc.createElement("file"); QDomElement nameEl = doc.createElement("name"); QDomText nameText = doc.createTextNode(filename.replace(QDir::homePath(), QString("~"))); nameEl.appendChild(nameText); fileEl.appendChild(nameEl); root.appendChild(fileEl); } QTextStream metastream(&f); metastream << doc.toString(); f.close(); } protected: - KoResource* byMd5(const QByteArray &md5) const override + KoResourceSP byMd5(const QByteArray &/*md5*/) const override { - return Policy::toResourcePointer(resourceByMD5(md5)); + return 0;//Policy::toResourcePointer(resourceByMD5(md5)); } - KoResource* byFileName(const QString &fileName) const override + KoResourceSP byFileName(const QString &/*fileName*/) const override { - return Policy::toResourcePointer(resourceByFilename(fileName)); + return 0;//Policy::toResourcePointer(resourceByFilename(fileName)); } private: - void addResourceToMd5Registry(PointerType resource) { + void addResourceToMd5Registry(QSharedPointer resource) { const QByteArray md5 = resource->md5(); if (!md5.isEmpty()) { m_resourcesByMd5.insert(md5, resource); } } - void removeResourceFromMd5Registry(PointerType resource) { + void removeResourceFromMd5Registry(QSharedPointer resource) { const QByteArray md5 = resource->md5(); if (!md5.isEmpty()) { m_resourcesByMd5.remove(md5); } } private: - QHash m_resourcesByName; - QHash m_resourcesByFilename; - QHash m_resourcesByMd5; + QHash> m_resourcesByName; + QHash> m_resourcesByFilename; + QHash> m_resourcesByMd5; - QList m_resourceBlackList; - QList m_resources; ///< list of resources in order of addition + QList> m_resourceBlackList; + QList> m_resources; ///< list of resources in order of addition QList m_observers; QString m_blackListFile; KoResourceTagStore* m_tagStore; }; -template > -class KoResourceServerSimpleConstruction : public KoResourceServer +template +class KoResourceServerSimpleConstruction : public KoResourceServer { public: KoResourceServerSimpleConstruction(const QString& type, const QString& extensions) - : KoResourceServer(type, extensions) + : KoResourceServer(type, extensions) { } - typename KoResourceServer::PointerType createResource( const QString & filename ) override { - return new T(filename); + QSharedPointer createResource( const QString & filename ) override { + return QSharedPointer(new T(filename)); } }; #endif // KORESOURCESERVER_H diff --git a/libs/widgets/KoResourceServerAdapter.cpp b/libs/widgets/KoResourceServerAdapter.cpp index 99ef8731ed..6debea192f 100644 --- a/libs/widgets/KoResourceServerAdapter.cpp +++ b/libs/widgets/KoResourceServerAdapter.cpp @@ -1,59 +1,59 @@ /* This file is part of the KDE project 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 "KoResourceServerAdapter.h" KoAbstractResourceServerAdapter::KoAbstractResourceServerAdapter(QObject *parent) : QObject(parent) { } KoAbstractResourceServerAdapter::~KoAbstractResourceServerAdapter() { } -void KoAbstractResourceServerAdapter::emitResourceAdded(KoResource* resource) +void KoAbstractResourceServerAdapter::emitResourceAdded(KoResourceSP resource) { emit resourceAdded(resource); } -void KoAbstractResourceServerAdapter::emitRemovingResource(KoResource* resource) +void KoAbstractResourceServerAdapter::emitRemovingResource(KoResourceSP resource) { emit removingResource(resource); } -void KoAbstractResourceServerAdapter::emitResourceChanged(KoResource* resource) +void KoAbstractResourceServerAdapter::emitResourceChanged(KoResourceSP resource) { emit resourceChanged(resource); } void KoAbstractResourceServerAdapter::emitTagsWereChanged() { emit tagsWereChanged(); } void KoAbstractResourceServerAdapter::emitTagCategoryWasAdded(const QString& tag) { emit tagCategoryWasAdded(tag); } void KoAbstractResourceServerAdapter::emitTagCategoryWasRemoved(const QString& tag) { emit tagCategoryWasRemoved(tag); } diff --git a/libs/widgets/KoResourceServerAdapter.h b/libs/widgets/KoResourceServerAdapter.h index 8922b21787..e21f262de4 100644 --- a/libs/widgets/KoResourceServerAdapter.h +++ b/libs/widgets/KoResourceServerAdapter.h @@ -1,353 +1,350 @@ /* This file is part of the KDE project Copyright (c) 2007 Sven Langkamp Copyright (C) 2011 Srikanth Tiyyagura Copyright (c) 2013 Sascha Suelzer 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 KO_RESOURCESERVER_ADAPTER_H_ #define KO_RESOURCESERVER_ADAPTER_H_ #include "KoResourceServer.h" #include #include #include "kritawidgets_export.h" /// The resource server adapter provides a adapter pattern for a templated resource server class KRITAWIDGETS_EXPORT KoAbstractResourceServerAdapter : public QObject { Q_OBJECT public: KoAbstractResourceServerAdapter(QObject *parent = 0); ~KoAbstractResourceServerAdapter() override; virtual void connectToResourceServer() = 0; - virtual QList resources() = 0; + virtual QList resources() = 0; - virtual QList serverResources() = 0; + virtual QList serverResources() = 0; - virtual bool addResource(KoResource* resource) = 0; - virtual bool removeResource(KoResource* resource) = 0; + virtual bool addResource(KoResourceSP resource) = 0; + virtual bool removeResource(KoResourceSP resource) = 0; virtual void removeResourceFile(const QString & filename) = 0; virtual void importResourceFile(const QString & filename, bool fileCreation = true) = 0; virtual QString extensions() const = 0; virtual void setCurrentTag(const QString& currentTag) = 0; virtual void enableResourceFiltering(bool tagSearch) = 0; virtual void updateServer() = 0; - virtual QStringList assignedTagsList(KoResource* resource) = 0; + virtual QStringList assignedTagsList(KoResourceSP resource) = 0; virtual QStringList tagNamesList() = 0; virtual void addTag(const QString& tag) = 0; - virtual void addTag(KoResource* resource, const QString& tag) = 0; - virtual void deleteTag(KoResource* resource, const QString& tag) = 0; + virtual void addTag(KoResourceSP resource, const QString& tag) = 0; + virtual void deleteTag(KoResourceSP resource, const QString& tag) = 0; virtual void searchTextChanged(const QString& searchString) = 0; // these call the server. virtual void tagCategoryMembersChanged() = 0; virtual void tagCategoryAdded(const QString& tag) = 0; virtual void tagCategoryRemoved(const QString& tag) = 0; virtual void setFilterIncludes(const QStringList& filteredNames) = 0; virtual QStringList searchTag(const QString& lineEditText) = 0; virtual void configureFilters(int filterType, bool enable) = 0; virtual QString serverType() const { return QString(); } virtual void setSortingEnabled(bool value) = 0; virtual bool sortingEnabled() const = 0; Q_SIGNALS: - void resourceAdded(KoResource*); - void removingResource(KoResource*); - void resourceChanged(KoResource*); + void resourceAdded(KoResourceSP ); + void removingResource(KoResourceSP ); + void resourceChanged(KoResourceSP ); void tagsWereChanged(); void tagCategoryWasAdded(const QString& tag); void tagCategoryWasRemoved(const QString& tag); protected: - void emitResourceAdded(KoResource* resource); - void emitRemovingResource(KoResource* resource); - void emitResourceChanged(KoResource* resource); + void emitResourceAdded(KoResourceSP resource); + void emitRemovingResource(KoResourceSP resource); + void emitResourceChanged(KoResourceSP resource); void emitTagsWereChanged(); void emitTagCategoryWasAdded(const QString& tag); void emitTagCategoryWasRemoved(const QString& tag); }; /** * The KoResourceServerAdapter provides adapter to a specific resource server * It provides a resource type independent interface to the server. */ -template > - class KoResourceServerAdapter : public KoAbstractResourceServerAdapter, public KoResourceServerObserver +template + class KoResourceServerAdapter : public KoAbstractResourceServerAdapter, public KoResourceServerObserver { - typedef KoResourceServer ServerType; - typedef typename Policy::PointerType PointerType; + typedef KoResourceServer ServerType; public: KoResourceServerAdapter(ServerType* resourceServer, QObject *parent = 0) : KoAbstractResourceServerAdapter(parent) , m_resourceServer(resourceServer) , m_sortingEnabled(false) { m_changeCounter = 0; m_oldChangeCounter = 0; m_enableFiltering = false; m_resourceFilter.setResourceServer(m_resourceServer); } ~KoResourceServerAdapter() override { if (m_resourceServer) m_resourceServer->removeObserver(this); } QString serverType() const override { if (m_resourceServer) { return m_resourceServer->type(); } return KoAbstractResourceServerAdapter::serverType(); } void unsetResourceServer() override { m_resourceServer = 0; } void connectToResourceServer() override { if (m_resourceServer) m_resourceServer->addObserver(this); } - QList resources() override + QList resources() override { if (! m_resourceServer) - return QList(); + return QList(); bool cacheDirty = serverResourceCacheInvalid(); if (cacheDirty) { - QList serverResources = + QList> serverResources = m_sortingEnabled ? m_resourceServer->sortedResources() : m_resourceServer->resources(); m_serverResources.clear(); - Q_FOREACH (PointerType resource, serverResources) { - m_serverResources.append(Policy::toResourcePointer(resource)); + Q_FOREACH (QSharedPointer resource, serverResources) { + m_serverResources.append(resource); } serverResourceCacheInvalid(false); } if (m_enableFiltering) { if (m_resourceFilter.filtersHaveChanged() || cacheDirty) { m_filteredResources = m_resourceFilter.filterResources(m_serverResources); } return m_filteredResources; } return m_serverResources; } - bool addResource(KoResource* resource) override + bool addResource(KoResourceSP resource) override { if (! m_resourceServer) return false; - T* res = dynamic_cast(resource); + QSharedPointer res = resource.dynamicCast(); if (res) { return m_resourceServer->addResource(res); } return false; } - bool removeResource(KoResource* resource) override + bool removeResource(KoResourceSP resource) override { if (! m_resourceServer) return false; - T* res = dynamic_cast(resource); + QSharedPointer res = resource.dynamicCast(); if (res) { - return m_resourceServer->removeResourceAndBlacklist(res); - } return false; } void importResourceFile(const QString & filename , bool fileCreation = true) override { if (! m_resourceServer) return; m_resourceServer->importResourceFile(filename, fileCreation); } void removeResourceFile(const QString & filename) override { if (!m_resourceServer) { return; } m_resourceServer->removeResourceFile(filename); } - void resourceAdded(PointerType resource) override { + void resourceAdded(QSharedPointer resource) override { serverResourceCacheInvalid(true); - emitResourceAdded(Policy::toResourcePointer(resource)); + emitResourceAdded(resource); } - void removingResource(PointerType resource) override { + void removingResource(QSharedPointer resource) override { serverResourceCacheInvalid(true); - emitRemovingResource(Policy::toResourcePointer(resource)); + emitRemovingResource(resource); } - void resourceChanged(PointerType resource) override { + void resourceChanged(QSharedPointer resource) override { serverResourceCacheInvalid(true); - emitResourceChanged(Policy::toResourcePointer(resource)); + emitResourceChanged(resource); } - void resourceChangedNoCacheInvalidation(PointerType resource) { - emitResourceChanged(Policy::toResourcePointer(resource)); + void resourceChangedNoCacheInvalidation(QSharedPointer resource) { + emitResourceChanged(resource); } void syncTaggedResourceView() override { serverResourceCacheInvalid(true); m_resourceFilter.rebuildCurrentTagFilenames(); emitTagsWereChanged(); } void syncTagAddition(const QString& tag) override { emitTagCategoryWasAdded(tag); } void syncTagRemoval(const QString& tag) override { emitTagCategoryWasRemoved(tag); } QString extensions() const override { if (! m_resourceServer) return QString(); return m_resourceServer->extensions(); } void setCurrentTag(const QString& resourceFileNames) override { serverResourceCacheInvalid(true); m_resourceFilter.setCurrentTag(resourceFileNames); } void enableResourceFiltering(bool enable) override { m_enableFiltering = enable; } void updateServer() override { emitRemovingResource(0); } - QStringList assignedTagsList(KoResource* resource) override { + QStringList assignedTagsList(KoResourceSP resource) override { return m_resourceServer->assignedTagsList(resource); } QStringList tagNamesList() override { return m_resourceServer->tagNamesList(); } void addTag(const QString& tag) override { m_resourceServer->addTag(0, tag); } - void addTag(KoResource* resource, const QString& tag) override { + void addTag(KoResourceSP resource, const QString& tag) override { m_resourceServer->addTag(resource, tag); } - void deleteTag(KoResource* resource, const QString& tag) override { + void deleteTag(KoResourceSP resource, const QString& tag) override { m_resourceServer->delTag(resource, tag); } void setFilterIncludes(const QStringList& filteredNames) override { m_resourceFilter.setInclusions(filteredNames); } void searchTextChanged(const QString& searchString) override { m_resourceFilter.setFilters(searchString); serverResourceCacheInvalid(true); } QStringList searchTag(const QString& lineEditText) override { return m_resourceServer->searchTag(lineEditText); } // called by model to notify server of change void tagCategoryMembersChanged() override { m_resourceServer->tagCategoryMembersChanged(); } void tagCategoryAdded(const QString& tag) override { m_resourceServer->tagCategoryAdded(tag); } void tagCategoryRemoved(const QString& tag) override { m_resourceServer->tagCategoryRemoved(tag); } - QList serverResources() override { + QList serverResources() override { return m_serverResources; } void configureFilters(int filterType, bool enable) override{ m_resourceFilter.configure(filterType,enable); } void setSortingEnabled(bool value) override { m_sortingEnabled = value; serverResourceCacheInvalid(true); } bool sortingEnabled() const override { return m_sortingEnabled; } protected: ServerType* resourceServer() const { return m_resourceServer; } protected: KoResourceFiltering m_resourceFilter; private: bool serverResourceCacheInvalid() const { return m_changeCounter != m_oldChangeCounter; } void serverResourceCacheInvalid(bool yes) { if (yes) { ++m_changeCounter; } else { m_oldChangeCounter = m_changeCounter; } } ServerType* m_resourceServer; unsigned int m_changeCounter; unsigned int m_oldChangeCounter; - QList m_serverResources; - QList m_filteredResources; + QList m_serverResources; + QList m_filteredResources; bool m_enableFiltering; bool m_sortingEnabled; }; #endif // KO_RESOURCESERVER_ADAPTER_H_ diff --git a/libs/widgets/KoResourceServerObserver.h b/libs/widgets/KoResourceServerObserver.h index 604c96900c..6906841d9d 100644 --- a/libs/widgets/KoResourceServerObserver.h +++ b/libs/widgets/KoResourceServerObserver.h @@ -1,77 +1,74 @@ /* This file is part of the KDE project 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 KORESOURCESERVEROBSERVER_H #define KORESOURCESERVEROBSERVER_H #include "kritawidgets_export.h" - -#include "KoResourceServerPolicies.h" - +#include /** * The KoResourceServerObserver class provides a interface to observe a KoResourceServer. * To receive notifications it needs to be added to the resource server. */ -template > +template class KoResourceServerObserver { public: virtual ~KoResourceServerObserver() {} - typedef typename Policy::PointerType PointerType; virtual void unsetResourceServer() = 0; /** * Will be called by the resource server after a resource is added * @param resource the added resource */ - virtual void resourceAdded(PointerType resource) = 0; + virtual void resourceAdded(QSharedPointer resource) = 0; /** * Will be called by the resource server before a resource will be removed * @param resource the resource which is going to be removed */ - virtual void removingResource(PointerType resource) = 0; + virtual void removingResource(QSharedPointer resource) = 0; /** * Will be called by the resource server when a resource is changed * @param resource the resource which is going to be removed */ - virtual void resourceChanged(PointerType resource) = 0; + virtual void resourceChanged(QSharedPointer resource) = 0; /** * Will be called by the resource server when resources are added or removed * from a tag category */ virtual void syncTaggedResourceView()=0; /** * Will be called by the resource server when a new tag category has been created */ virtual void syncTagAddition(const QString& tag)=0; /** * Will be called by the resource server when a new tag category has been deleted */ virtual void syncTagRemoval(const QString& tag)=0; }; #endif // KORESOURCESERVEROBSERVER_H diff --git a/libs/widgets/KoResourceServerPolicies.h b/libs/widgets/KoResourceServerPolicies.h index 04f51efcef..b1296c2c93 100644 --- a/libs/widgets/KoResourceServerPolicies.h +++ b/libs/widgets/KoResourceServerPolicies.h @@ -1,49 +1,49 @@ /* This file is part of the KDE project Copyright (c) 2014 Dmitry Kazakov 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 KORESOURCESERVERPOLICIES_H #define KORESOURCESERVERPOLICIES_H #include "kritawidgets_export.h" class KoResource; template struct PointerStoragePolicy { typedef T* PointerType; static inline void deleteResource(PointerType resource) { delete resource; } - static inline KoResource* toResourcePointer(PointerType resource) { + static inline KoResource *toResourcePointer(PointerType resource) { return resource; } }; template struct SharedPointerStoragePolicy { typedef SharedPointer PointerType; static inline void deleteResource(PointerType resource) { Q_UNUSED(resource); } - static inline KoResource* toResourcePointer(PointerType resource) { + static inline KoResource *toResourcePointer(PointerType resource) { return resource.data(); } }; #endif // KORESOURCESERVERPOLICIES_H diff --git a/libs/widgets/KoResourceServerProvider.cpp b/libs/widgets/KoResourceServerProvider.cpp index dd463e3a43..641dbabf85 100644 --- a/libs/widgets/KoResourceServerProvider.cpp +++ b/libs/widgets/KoResourceServerProvider.cpp @@ -1,198 +1,200 @@ /* 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 using namespace std; class GradientResourceServer : public KoResourceServer { public: GradientResourceServer(const QString& type, const QString& extensions) : KoResourceServer(type, extensions) , m_foregroundToTransparent(0) , m_foregroundToBackground(0) { insertSpecialGradients(); } void insertSpecialGradients() { const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); QList stops; - KoStopGradient* gradient = new KoStopGradient(); + KoStopGradientSP gradient(new KoStopGradient()); gradient->setType(QGradient::LinearGradient); gradient->setName("Foreground to Transparent"); stops << KoGradientStop(0.0, KoColor(Qt::black, cs)) << KoGradientStop(1.0, KoColor(QColor(0, 0, 0, 0), cs)); gradient->setStops(stops); gradient->setValid(true); gradient->setPermanent(true); addResource(gradient, false, true); m_foregroundToTransparent = gradient; - gradient = new KoStopGradient(); + gradient.reset(new KoStopGradient()); gradient->setType(QGradient::LinearGradient); gradient->setName("Foreground to Background"); stops.clear(); stops << KoGradientStop(0.0, KoColor(Qt::black, cs)) << KoGradientStop(1.0, KoColor(Qt::white, cs)); gradient->setStops(stops); gradient->setValid(true); gradient->setPermanent(true); addResource(gradient, false, true); m_foregroundToBackground = gradient; } private: friend class KoResourceBundle; - KoAbstractGradient* createResource( const QString & filename ) override { + KoAbstractGradientSP createResource( const QString & filename ) override { QString fileExtension; int index = filename.lastIndexOf('.'); if (index != -1) fileExtension = filename.mid(index).toLower(); - KoAbstractGradient* grad = 0; + KoAbstractGradientSP grad; - if(fileExtension == ".svg" || fileExtension == ".kgr") - grad = new KoStopGradient(filename); - else if(fileExtension == ".ggr" ) - grad = new KoSegmentGradient(filename); + if(fileExtension == ".svg" || fileExtension == ".kgr") { + grad.reset(new KoStopGradient(filename)); + } + else if(fileExtension == ".ggr" ) { + grad.reset(new KoSegmentGradient(filename)); + } return grad; } - QList< KoAbstractGradient* > sortedResources() override { - QList< KoAbstractGradient* > resources = KoResourceServer::sortedResources(); - QList< KoAbstractGradient* > sorted; + QList< KoAbstractGradientSP > sortedResources() override { + QList< KoAbstractGradientSP > resources = KoResourceServer::sortedResources(); + QList< KoAbstractGradientSP > sorted; if (m_foregroundToTransparent && resources.contains(m_foregroundToTransparent)) { sorted.append(resources.takeAt(resources.indexOf(m_foregroundToTransparent))); } if (m_foregroundToBackground && resources.contains(m_foregroundToBackground)) { sorted.append(resources.takeAt(resources.indexOf(m_foregroundToBackground))); } return sorted + resources; } - KoAbstractGradient* m_foregroundToTransparent; - KoAbstractGradient* m_foregroundToBackground; + KoAbstractGradientSP m_foregroundToTransparent; + KoAbstractGradientSP m_foregroundToBackground; }; struct Q_DECL_HIDDEN KoResourceServerProvider::Private { - KoResourceServer* patternServer; - KoResourceServer* gradientServer; - KoResourceServer* paletteServer; + KoResourceServer *patternServer; + KoResourceServer *gradientServer; + KoResourceServer *paletteServer; KoResourceServer *svgSymbolCollectionServer; - KoResourceServer* gamutMaskServer; + KoResourceServer *gamutMaskServer; }; KoResourceServerProvider::KoResourceServerProvider() : d(new Private) { d->patternServer = new KoResourceServerSimpleConstruction("patterns", "*.pat:*.jpg:*.gif:*.png:*.tif:*.xpm:*.bmp" ); d->patternServer->loadResources(blacklistFileNames(d->patternServer->fileNames(), d->patternServer->blackListedFiles())); d->gradientServer = new GradientResourceServer("gradients", "*.kgr:*.svg:*.ggr"); d->gradientServer->loadResources(blacklistFileNames(d->gradientServer->fileNames(), d->gradientServer->blackListedFiles())); d->paletteServer = new KoResourceServerSimpleConstruction("palettes", "*.kpl:*.gpl:*.pal:*.act:*.aco:*.css:*.colors:*.xml:*.sbz"); d->paletteServer->loadResources(blacklistFileNames(d->paletteServer->fileNames(), d->paletteServer->blackListedFiles())); d->svgSymbolCollectionServer = new KoResourceServerSimpleConstruction("symbols", "*.svg"); d->svgSymbolCollectionServer->loadResources(blacklistFileNames(d->svgSymbolCollectionServer->fileNames(), d->svgSymbolCollectionServer->blackListedFiles())); d->gamutMaskServer = new KoResourceServerSimpleConstruction("gamutmasks", "*.kgm"); d->gamutMaskServer->loadResources(blacklistFileNames(d->gamutMaskServer->fileNames(), d->gamutMaskServer->blackListedFiles())); } KoResourceServerProvider::~KoResourceServerProvider() { delete d->patternServer; delete d->gradientServer; delete d->paletteServer; delete d->svgSymbolCollectionServer; delete d->gamutMaskServer; delete d; } Q_GLOBAL_STATIC(KoResourceServerProvider, s_instance); -KoResourceServerProvider* KoResourceServerProvider::instance() +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() +KoResourceServer *KoResourceServerProvider::patternServer() { return d->patternServer; } -KoResourceServer* KoResourceServerProvider::gradientServer() +KoResourceServer *KoResourceServerProvider::gradientServer() { return d->gradientServer; } -KoResourceServer* KoResourceServerProvider::paletteServer() +KoResourceServer *KoResourceServerProvider::paletteServer() { return d->paletteServer; } KoResourceServer *KoResourceServerProvider::svgSymbolCollectionServer() { return d->svgSymbolCollectionServer; } -KoResourceServer* KoResourceServerProvider::gamutMaskServer() +KoResourceServer *KoResourceServerProvider::gamutMaskServer() { return d->gamutMaskServer; } diff --git a/libs/widgets/KoResourceServerProvider.h b/libs/widgets/KoResourceServerProvider.h index a9f2798c32..e2553def80 100644 --- a/libs/widgets/KoResourceServerProvider.h +++ b/libs/widgets/KoResourceServerProvider.h @@ -1,76 +1,75 @@ /* This file is part of the KDE project Copyright (c) 1999 Matthias Elter Copyright (c) 2003 Patrick Julien Copyright (c) 2005 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 KORESOURCESERVERPROVIDER_H #define KORESOURCESERVERPROVIDER_H #include #include #include #include "KoResourceServer.h" #include #include #include #include #include /** * Provides default resource servers for gradients, patterns and palettes */ class KRITAWIDGETS_EXPORT KoResourceServerProvider : public QObject { Q_OBJECT public: KoResourceServerProvider(); ~KoResourceServerProvider() override; static KoResourceServerProvider* instance(); /** * @brief blacklistFileNames filters the filenames with the list of blacklisted file names * @param fileNames all files * @param blacklistedFileNames the files we don't want * @return the result */ static QStringList blacklistFileNames(QStringList fileNames, const QStringList &blacklistedFileNames); - - KoResourceServer* patternServer(); - KoResourceServer* gradientServer(); - KoResourceServer* paletteServer(); - KoResourceServer* svgSymbolCollectionServer(); - KoResourceServer* gamutMaskServer(); + KoResourceServer *patternServer(); + KoResourceServer *gradientServer(); + KoResourceServer *paletteServer(); + KoResourceServer *svgSymbolCollectionServer(); + KoResourceServer *gamutMaskServer(); private: KoResourceServerProvider(const KoResourceServerProvider&); KoResourceServerProvider operator=(const KoResourceServerProvider&); private: struct Private; Private* const d; }; #endif // KORESOURCESERVERPROVIDER_H diff --git a/libs/widgets/KoResourceTagStore.cpp b/libs/widgets/KoResourceTagStore.cpp index 8e8e9ead23..cb5522da82 100644 --- a/libs/widgets/KoResourceTagStore.cpp +++ b/libs/widgets/KoResourceTagStore.cpp @@ -1,417 +1,417 @@ /* This file is part of the KDE project Copyright (c) 2011 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 "KoResourceTagStore.h" #include #include #include #include #include #include #include #include #define BLACKLISTED "blacklisted" ///< xml tag for blacklisted tags static const QStringList krita3PresetSystemTags = {"Ink", "Block", "Wet", "FX", "Erasers", "Circle", "Smudge", "Mix", "PixelArt", "ink", "sketch", "demo", "paint"}; class Q_DECL_HIDDEN KoResourceTagStore::Private { public: QMultiHash md5ToTag; QMultiHash identifierToTag; QHash tagList; QStringList blacklistedTags; KoResourceServerBase *resourceServer; }; KoResourceTagStore::KoResourceTagStore(KoResourceServerBase *resourceServer) : d(new Private) { d->resourceServer = resourceServer; } KoResourceTagStore::~KoResourceTagStore() { serializeTags(); delete d; } -QStringList KoResourceTagStore::assignedTagsList(const KoResource* resource) const +QStringList KoResourceTagStore::assignedTagsList(const KoResourceSP resource) const { if (!resource) return QStringList(); QStringList tags = d->md5ToTag.values(resource->md5()); tags += d->identifierToTag.values(resource->filename()); tags.removeDuplicates(); return tags; } -void KoResourceTagStore::removeResource(const KoResource *resource) +void KoResourceTagStore::removeResource(const KoResourceSP resource) { QStringList tags = assignedTagsList(resource); d->md5ToTag.remove(resource->md5()); d->identifierToTag.remove(resource->filename()); Q_FOREACH (const QString &tag, tags) { if (d->tagList.contains(tag)) { if (d->tagList[tag] > 0) { d->tagList[tag]--; } } } } QStringList KoResourceTagStore::tagNamesList() const { QStringList tagList = d->tagList.uniqueKeys(); Q_FOREACH(const QString &tag, d->blacklistedTags) { tagList.removeAll(tag); } return tagList; } -void KoResourceTagStore::addTag(KoResource* resource, const QString& tag) +void KoResourceTagStore::addTag(KoResourceSP resource, const QString& tag) { // if (d->resourceServer->type() == "paintoppresets" && resource) { // qDebug() << "\t\t\taddTag" << tag << resource->filename() << d->tagList[tag] << d->md5ToTag.value(resource->md5()) << d->identifierToTag.values(resource->filename()); // } if (d->blacklistedTags.contains(tag)) { d->blacklistedTags.removeAll(tag); } if (!d->tagList.contains(tag)) { d->tagList.insert(tag, 0); } if (resource) { bool added = false; if (!d->md5ToTag.contains(resource->md5(), tag)) { added = true; d->md5ToTag.insert(resource->md5(), tag); } if (!d->identifierToTag.contains(resource->filename())) { added = true; d->identifierToTag.insert(resource->filename(), tag); } if (added) { d->tagList[tag]++; } } // if (d->resourceServer->type() == "paintoppresets" && resource) { // qDebug() << "\t\t\t\tafter addTag" << tag << resource->filename() << d->tagList[tag] << d->md5ToTag.value(resource->md5()) << d->identifierToTag.values(resource->filename()); // } } -void KoResourceTagStore::delTag(KoResource* resource, const QString& tag) +void KoResourceTagStore::delTag(KoResourceSP resource, const QString& tag) { int res = d->md5ToTag.remove(resource->md5(), tag); res += d->identifierToTag.remove(resource->filename(), tag); if (res > 0) { // decrease the usecount for this tag if (d->tagList.contains(tag)) { if (d->tagList[tag] > 0) { d->tagList[tag]--; } } } } void KoResourceTagStore::delTag(const QString& tag) { Q_FOREACH (const QByteArray &res, d->md5ToTag.keys(tag)) { d->md5ToTag.remove(res, tag); } Q_FOREACH (const QString &identifier, d->identifierToTag.keys(tag)) { d->identifierToTag.remove(identifier, tag); } Q_ASSERT(!d->md5ToTag.values().contains(tag)); Q_ASSERT(!d->identifierToTag.values().contains(tag)); d->tagList.remove(tag); d->blacklistedTags << tag; serializeTags(); } QStringList KoResourceTagStore::searchTag(const QString& query) const { QStringList tagsList = query.split(QRegExp("[,]\\s*"), QString::SkipEmptyParts); if (tagsList.isEmpty()) { return QStringList(); } - QSet resources; + QSet resources; Q_FOREACH (QString tag, tagsList) { Q_FOREACH (const QByteArray &md5, d->md5ToTag.keys(tag)) { - KoResource *res = d->resourceServer->byMd5(md5); + KoResourceSP res = d->resourceServer->byMd5(md5); if (res) resources << res; } Q_FOREACH (const QString &identifier, d->identifierToTag.keys(tag)) { - KoResource *res = d->resourceServer->byFileName(identifier); + KoResourceSP res = d->resourceServer->byFileName(identifier); if (res) resources << res; } } QStringList filenames; - Q_FOREACH (const KoResource *res, resources) { + Q_FOREACH (const KoResourceSP res, resources) { if (res) { filenames << res->shortFilename(); } } return filenames; } void KoResourceTagStore::loadTags() { QStringList tagFiles = KoResourcePaths::findDirs("tags"); Q_FOREACH (const QString &tagFile, tagFiles) { QString fileName = tagFile + d->resourceServer->type() + "_tags.xml"; if (QFileInfo(fileName).exists()) { readXMLFile(fileName); } } } void KoResourceTagStore::clearOldSystemTags() { if (d->resourceServer->type() == "paintoppresets") { // qDebug() << "clearOldSystemTags" << d->tagList; Q_FOREACH(const QString &systemTag, krita3PresetSystemTags) { // qDebug() << "\t" << systemTag << d->tagList[systemTag]; if (d->tagList[systemTag] == 0) { d->tagList.remove(systemTag); } } } } void KoResourceTagStore::writeXMLFile(const QString &tagstore) { QFile f(tagstore); if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { warnWidgets << "Cannot write meta information to '" << tagstore << "'."; return; } QDomDocument doc; QDomElement root; QDomDocument docTemp("tags"); doc = docTemp; doc.appendChild(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"")); root = doc.createElement("tags"); doc.appendChild(root); - QSet taggedResources; + QSet taggedResources; Q_FOREACH (const QByteArray &md5, d->md5ToTag.keys()) { - KoResource *res = d->resourceServer->byMd5(md5); + KoResourceSP res = d->resourceServer->byMd5(md5); if (res) { taggedResources << res; } } Q_FOREACH (const QString &identifier, d->identifierToTag.keys()) { - KoResource *res = d->resourceServer->byFileName(identifier); + KoResourceSP res = d->resourceServer->byFileName(identifier); if (res) { taggedResources << res; } } - Q_FOREACH (const KoResource *res, taggedResources) { + Q_FOREACH (const KoResourceSP res, taggedResources) { QDomElement resourceEl = doc.createElement("resource"); resourceEl.setAttribute("identifier", res->filename().replace(QDir::homePath(), QString("~"))); resourceEl.setAttribute("md5", QString(res->md5().toBase64())); Q_FOREACH (const QString &tag, assignedTagsList(res)) { QDomElement tagEl = doc.createElement("tag"); tagEl.setAttribute(BLACKLISTED, "false"); tagEl.appendChild(doc.createTextNode(tag)); resourceEl.appendChild(tagEl); } root.appendChild(resourceEl); } // Now write empty tags Q_FOREACH (const QString &tag, d->tagList.uniqueKeys()) { if (d->tagList[tag] == 0) { QDomElement resourceEl = doc.createElement("resource"); resourceEl.setAttribute("identifier", "dummy"); QDomElement tagEl = doc.createElement("tag"); tagEl.setAttribute(BLACKLISTED, d->blacklistedTags.contains(tag) ? "true" : "false"); tagEl.appendChild(doc.createTextNode(tag)); resourceEl.appendChild(tagEl); root.appendChild(resourceEl); } } // Now write blacklisted tags. Q_FOREACH (const QString &tag, d->blacklistedTags) { if (d->tagList[tag] == 0) { QDomElement resourceEl = doc.createElement("resource"); resourceEl.setAttribute("identifier", "dummy"); QDomElement tagEl = doc.createElement("tag"); tagEl.setAttribute(BLACKLISTED, "true"); tagEl.appendChild(doc.createTextNode(tag)); resourceEl.appendChild(tagEl); root.appendChild(resourceEl); } } QTextStream metastream(&f); metastream.setCodec("UTF-8"); metastream << doc.toString(); f.close(); } void KoResourceTagStore::readXMLFile(const QString &tagstore) { QString inputFile; if (QFile::exists(tagstore)) { inputFile = tagstore; } else { return; } // qDebug() << "\treadXMLFile()." << tagstore << d->resourceServer->type() << "Server has" << d->resourceServer->resourceCount() << "resources"; if (d->resourceServer->type() == "paintoppresets") { // Q_FOREACH(const QString &line, kisBacktrace().split("\n")) { // qDebug() << line; // } } QFile f(inputFile); if (!f.open(QIODevice::ReadOnly)) { qWarning() << "Could not open tag file" << tagstore; return; } QDomDocument doc; if (!doc.setContent(&f)) { warnWidgets << "The file could not be parsed."; return; } QDomElement root = doc.documentElement(); if (root.tagName() != "tags") { warnWidgets << "The file doesn't seem to be of interest."; return; } QDomNodeList resourceNodesList = root.childNodes(); for (int i = 0; i < resourceNodesList.count(); i++) { QByteArray resourceMD5; QString identifier; QDomElement element = resourceNodesList.at(i).toElement(); if (element.tagName() == "resource") { - KoResource *resByMd5 = 0; - KoResource *resByFileName = 0; + KoResourceSP resByMd5 = 0; + KoResourceSP resByFileName = 0; if (element.hasAttribute("md5")) { resourceMD5 = QByteArray::fromBase64(element.attribute("md5").toLatin1()); resByMd5 = d->resourceServer->byMd5(resourceMD5); } if (element.hasAttribute("identifier")) { identifier = element.attribute("identifier"); QFileInfo fi(identifier); resByFileName = d->resourceServer->byFileName(fi.fileName()); } // qDebug() << "\t\tmd5" << QString::fromLatin1(resourceMD5.toHex()) << "resByMd5" << resByMd5 << "identifier" << identifier << "resByFileName" << resByFileName; if (identifier == "dummy") { QDomNodeList tagNodesList = resourceNodesList.at(i).childNodes(); for (int j = 0; j < tagNodesList.count() ; j++) { QDomElement tagEl = tagNodesList.at(j).toElement(); bool blacklisted = (tagEl.attribute(BLACKLISTED, "false") == "true"); if (blacklisted || d->blacklistedTags.contains(tagEl.text())) { if (!d->blacklistedTags.contains(tagEl.text())) { d->blacklistedTags << tagEl.text(); } } else { addTag(0, tagEl.text()); } } } else { - KoResource *res = 0; + KoResourceSP res = 0; if (resByMd5 && resByFileName && (resByMd5 != resByFileName)) { warnWidgets << "MD5sum and filename point to different resources -- was the resource renamed? We go with md5"; res = resByMd5; } else if (!resByMd5 && resByFileName) { // We didn't find the resource by md5, but did find it by filename, so take that one res = resByFileName; } else { res = resByMd5; } QDomNodeList tagNodesList = resourceNodesList.at(i).childNodes(); for (int j = 0; j < tagNodesList.count() ; j++) { QDomElement tagEl = tagNodesList.at(j).toElement(); bool blacklisted = (tagEl.attribute(BLACKLISTED, "false") == "true"); if (blacklisted || d->blacklistedTags.contains(tagEl.text())) { if (!d->blacklistedTags.contains(tagEl.text())) { d->blacklistedTags << tagEl.text(); } } else { if (res) { addTag(res, tagEl.text()); } d->md5ToTag.insert(resourceMD5, tagEl.text()); d->identifierToTag.insert(identifier, tagEl.text()); } } } } } // qDebug() << "Done reading XML file from" << tagstore << d->tagList; } void KoResourceTagStore::serializeTags() { writeXMLFile(KoResourcePaths::saveLocation("tags") + d->resourceServer->type() + "_tags.xml"); } diff --git a/libs/widgets/KoResourceTagStore.h b/libs/widgets/KoResourceTagStore.h index d66046790c..4263d64982 100644 --- a/libs/widgets/KoResourceTagStore.h +++ b/libs/widgets/KoResourceTagStore.h @@ -1,84 +1,85 @@ /* This file is part of the KDE project Copyright (c) 2011 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 */ #ifndef KORESOURCETAGSTORE_H #define KORESOURCETAGSTORE_H #include #include "kritawidgets_export.h" +#include + class KoResourceServerBase; -class KoResource; class QStringList; class QString; /** * KoResourceTagging allows to add and delete tags to resources and also search resources using tags */ class KRITAWIDGETS_EXPORT KoResourceTagStore { public: /** * Constructs a KoResourceTagging object * */ explicit KoResourceTagStore(KoResourceServerBase *resourceServer); ~KoResourceTagStore(); - QStringList assignedTagsList(const KoResource *resource) const; + QStringList assignedTagsList(const KoResourceSP resource) const; /// remote the given resource from the tagstore - void removeResource(const KoResource *resource); + void removeResource(const KoResourceSP resource); /// Add the given tag to the tag store. The resource can be empty, in which case /// the tag is added but unused - void addTag(KoResource* resource, const QString& tag); + void addTag(KoResourceSP resource, const QString& tag); /// Remove the given tag for the given resource. It will be blacklisted if there are no users left. - void delTag(KoResource* resource, const QString& tag); + void delTag(KoResourceSP resource, const QString& tag); /// Remove the tag altogether. It will be blacklisted, too. void delTag(const QString& tag); /// @return a list of all the tags in this store QStringList tagNamesList() const; /// Return a list of filenames for the given tag QStringList searchTag(const QString& query) const; void loadTags(); void clearOldSystemTags(); void serializeTags(); private: friend class KoResourceTaggingTest; void readXMLFile(const QString &tagstore); void writeXMLFile(const QString &tagstore); class Private; Private * const d; }; #endif // KORESOURCETAGSTORE_H diff --git a/libs/widgets/KoResourceTaggingManager.cpp b/libs/widgets/KoResourceTaggingManager.cpp index d149afae42..ead145a4ec 100644 --- a/libs/widgets/KoResourceTaggingManager.cpp +++ b/libs/widgets/KoResourceTaggingManager.cpp @@ -1,397 +1,397 @@ /* * This file is part of the KDE project * Copyright (c) 2002 Patrick Julien * Copyright (c) 2007 Jan Hambrecht * Copyright (c) 2007 Sven Langkamp * Copyright (C) 2011 Srikanth Tiyyagura * Copyright (c) 2011 José Luis Vergara * Copyright (c) 2013 Sascha Suelzer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoResourceTaggingManager.h" #include #include #include #include #include #include #include #include "KoTagFilterWidget.h" #include "KoTagChooserWidget.h" #include "KoLegacyResourceModel.h" #include #include "KoResourceItemChooserContextMenu.h" #include class TaggedResourceSet { public: TaggedResourceSet() {} - TaggedResourceSet(const QString& tagName, const QList& resources) + TaggedResourceSet(const QString& tagName, const QList& resources) : tagName(tagName) , resources(resources) {} QString tagName; - QList resources; + QList resources; }; class KoResourceTaggingManager::Private { public: QString currentTag; - QList originalResources; + QList originalResources; TaggedResourceSet lastDeletedTag; KoTagChooserWidget* tagChooser; KoTagFilterWidget* tagFilter; QCompleter* tagCompleter; QPointer model; }; KoResourceTaggingManager::KoResourceTaggingManager(KoLegacyResourceModel *model, QWidget* parent) : QObject(parent) , d(new Private()) { d->model = model; d->tagChooser = new KoTagChooserWidget(parent); d->tagChooser->addReadOnlyItem("All"); // not translatable until other tags made translatable! d->tagChooser->addItems(d->model->tagNamesList()); d->tagFilter = new KoTagFilterWidget(parent); connect(d->tagChooser, SIGNAL(tagChosen(QString)), this, SLOT(tagChooserIndexChanged(QString))); connect(d->tagChooser, SIGNAL(newTagRequested(QString)), this, SLOT(contextCreateNewTag(QString))); connect(d->tagChooser, SIGNAL(tagDeletionRequested(QString)), this, SLOT(removeTagFromComboBox(QString))); connect(d->tagChooser, SIGNAL(tagRenamingRequested(QString,QString)), this, SLOT(renameTag(QString,QString))); connect(d->tagChooser, SIGNAL(tagUndeletionRequested(QString)), this, SLOT(undeleteTag(QString))); connect(d->tagChooser, SIGNAL(tagUndeletionListPurgeRequested()), this, SLOT(purgeTagUndeleteList())); connect(d->tagFilter, SIGNAL(saveButtonClicked()), this, SLOT(tagSaveButtonPressed())); connect(d->tagFilter, SIGNAL(filterTextChanged(QString)), this, SLOT(tagSearchLineEditTextChanged(QString))); connect(d->model, SIGNAL(tagBoxEntryAdded(QString)), this, SLOT(syncTagBoxEntryAddition(QString))); connect(d->model, SIGNAL(tagBoxEntryRemoved(QString)), this, SLOT(syncTagBoxEntryRemoval(QString))); connect(d->model, SIGNAL(tagBoxEntryModified()), this, SLOT(syncTagBoxEntries())); // FIXME: fix tag completer // d->tagCompleter = new QCompleter(this); // d->tagSearchLineEdit->setCompleter(d->tagCompleter); syncTagBoxEntries(); } KoResourceTaggingManager::~KoResourceTaggingManager() { delete d; } void KoResourceTaggingManager::showTaggingBar(bool show) { show ? d->tagFilter->show() : d->tagFilter->hide(); show ? d->tagChooser->show() : d->tagChooser->hide(); blockSignals(!show); QString tag("All"); if (show) { KConfigGroup group = KSharedConfig::openConfig()->group("SelectedTags"); tag = group.readEntry(d->model->serverType(), "All"); } int idx = d->tagChooser->findIndexOf(tag); if (idx < 0) idx = 0; d->tagChooser->setCurrentIndex(idx); } void KoResourceTaggingManager::purgeTagUndeleteList() { d->lastDeletedTag = TaggedResourceSet(); d->tagChooser->setUndeletionCandidate(QString()); } void KoResourceTaggingManager::undeleteTag(const QString & tagToUndelete) { QString tagName = tagToUndelete; QStringList allTags = availableTags(); if (allTags.contains(tagName)) { bool ok; tagName = QInputDialog::getText( d->tagChooser, i18n("Unable to undelete tag"), i18n("The tag you are trying to undelete already exists in tag list.
    Please enter a new, unique name for it.
    "), QLineEdit::Normal, tagName, &ok); if (!ok || allTags.contains(tagName) || tagName.isEmpty()) { QMessageBox msgBox; msgBox.setIcon(QMessageBox::Warning); msgBox.setText(i18n("Tag was not undeleted.")); msgBox.exec(); return; } } - QList serverResources = d->model->serverResources(); + QList serverResources = d->model->serverResources(); - Q_FOREACH (KoResource * resource, d->lastDeletedTag.resources) { + Q_FOREACH(KoResourceSP resource, d->lastDeletedTag.resources) { if (serverResources.contains(resource)) { addResourceTag(resource, tagName); } } d->model->tagCategoryAdded(tagName); d->tagChooser->setCurrentIndex(d->tagChooser->findIndexOf(tagName)); d->tagChooser->setUndeletionCandidate(QString()); d->lastDeletedTag = TaggedResourceSet(); } QStringList KoResourceTaggingManager::availableTags() const { return d->tagChooser->allTags(); } -void KoResourceTaggingManager::addResourceTag(KoResource* resource, const QString& tagName) +void KoResourceTaggingManager::addResourceTag(KoResourceSP resource, const QString& tagName) { QStringList tagsList = d->model->assignedTagsList(resource); if (tagsList.isEmpty()) { d->model->addTag(resource, tagName); } else { Q_FOREACH (const QString & tag, tagsList) { if (tag.compare(tagName)) { d->model->addTag(resource, tagName); } } } } void KoResourceTaggingManager::syncTagBoxEntryAddition(const QString& tag) { d->tagChooser->insertItem(tag); } void KoResourceTaggingManager::contextCreateNewTag(const QString& tag) { if (!tag.isEmpty()) { d->model->addTag(0, tag); d->model->tagCategoryAdded(tag); d->tagChooser->setCurrentIndex(d->tagChooser->findIndexOf(tag)); updateTaggedResourceView(); } } -void KoResourceTaggingManager::contextCreateNewTag(KoResource* resource , const QString& tag) +void KoResourceTaggingManager::contextCreateNewTag(KoResourceSP resource , const QString& tag) { if (!tag.isEmpty()) { d->model->tagCategoryAdded(tag); if (resource) { addResourceTag(resource, tag); } } } void KoResourceTaggingManager::syncTagBoxEntryRemoval(const QString& tag) { d->tagChooser->removeItem(tag); } void KoResourceTaggingManager::syncTagBoxEntries() { QStringList tags = d->model->tagNamesList(); tags.sort(); Q_FOREACH (const QString &tag, tags) { d->tagChooser->insertItem(tag); } } -void KoResourceTaggingManager::contextAddTagToResource(KoResource* resource, const QString& tag) +void KoResourceTaggingManager::contextAddTagToResource(KoResourceSP resource, const QString& tag) { addResourceTag(resource, tag); d->model->tagCategoryMembersChanged(); updateTaggedResourceView(); } -void KoResourceTaggingManager::contextRemoveTagFromResource(KoResource* resource, const QString& tag) +void KoResourceTaggingManager::contextRemoveTagFromResource(KoResourceSP resource, const QString& tag) { removeResourceTag(resource, tag); d->model->tagCategoryMembersChanged(); updateTaggedResourceView(); } void KoResourceTaggingManager::removeTagFromComboBox(const QString &tag) { - QList resources = d->model->currentlyVisibleResources(); - Q_FOREACH (KoResource * resource, resources) { + QList resources = d->model->currentlyVisibleResources(); + Q_FOREACH (KoResourceSP resource, resources) { removeResourceTag(resource, tag); } d->model->tagCategoryRemoved(tag); d->lastDeletedTag = TaggedResourceSet(tag, resources); d->tagChooser->setUndeletionCandidate(tag); } -void KoResourceTaggingManager::removeResourceTag(KoResource* resource, const QString& tagName) +void KoResourceTaggingManager::removeResourceTag(KoResourceSP resource, const QString& tagName) { QStringList tagsList = d->model->assignedTagsList(resource); Q_FOREACH (const QString & oldName, tagsList) { if (!oldName.compare(tagName)) { d->model->deleteTag(resource, oldName); } } } void KoResourceTaggingManager::renameTag(const QString &oldName, const QString& newName) { if (!d->model->tagNamesList().contains(newName)) { - QList resources = d->model->currentlyVisibleResources(); + QList resources = d->model->currentlyVisibleResources(); - Q_FOREACH (KoResource * resource, resources) { + Q_FOREACH (KoResourceSP resource, resources) { removeResourceTag(resource, oldName); addResourceTag(resource, newName); } contextCreateNewTag(newName); d->model->tagCategoryRemoved(oldName); d->model->tagCategoryAdded(newName); } } void KoResourceTaggingManager::updateTaggedResourceView() { d->model->setCurrentTag(d->currentTag); d->model->updateServer(); d->originalResources = d->model->currentlyVisibleResources(); emit updateView(); } void KoResourceTaggingManager::tagChooserIndexChanged(const QString& lineEditText) { if (!d->tagChooser->selectedTagIsReadOnly()) { d->currentTag = lineEditText; d->tagFilter->allowSave(true); d->model->enableResourceFiltering(true); } else { d->model->enableResourceFiltering(false); d->tagFilter->allowSave(false); d->currentTag.clear(); } d->tagFilter->clear(); updateTaggedResourceView(); } void KoResourceTaggingManager::tagSearchLineEditTextChanged(const QString& lineEditText) { if (d->tagChooser->selectedTagIsReadOnly()) { d->model->enableResourceFiltering(!lineEditText.isEmpty()); } else { d->model->enableResourceFiltering(true); } d->model->searchTextChanged(lineEditText); d->model->updateServer(); ///FIXME: fix completer // d->tagCompleter = new QCompleter(tagNamesList(lineEditText),this); // d->tagSearchLineEdit->setCompleter(d->tagCompleter); emit updateView(); } void KoResourceTaggingManager::tagSaveButtonPressed() { if (!d->tagChooser->selectedTagIsReadOnly()) { - QList newResources = d->model->currentlyVisibleResources(); - Q_FOREACH (KoResource * oldRes, d->originalResources) { + QList newResources = d->model->currentlyVisibleResources(); + Q_FOREACH (KoResourceSP oldRes, d->originalResources) { if (!newResources.contains(oldRes)) removeResourceTag(oldRes, d->currentTag); } - Q_FOREACH (KoResource * newRes, newResources) { + Q_FOREACH (KoResourceSP newRes, newResources) { if (!d->originalResources.contains(newRes)) addResourceTag(newRes, d->currentTag); } d->model->tagCategoryMembersChanged(); } updateTaggedResourceView(); } -void KoResourceTaggingManager::contextMenuRequested(KoResource* resource, const QStringList& resourceTags, const QPoint& pos) +void KoResourceTaggingManager::contextMenuRequested(KoResourceSP resource, const QStringList& resourceTags, const QPoint& pos) { /* no visible tag chooser usually means no intended tag interaction, * context menu makes no sense then either */ if (!resource || !d->tagChooser->isVisible()) return; KoResourceItemChooserContextMenu menu(resource, resourceTags, d->tagChooser->currentlySelectedTag(), d->tagChooser->allTags()); - connect(&menu, SIGNAL(resourceTagAdditionRequested(KoResource*,QString)), - this, SLOT(contextAddTagToResource(KoResource*,QString))); + connect(&menu, SIGNAL(resourceTagAdditionRequested(KoResourceSP,QString)), + this, SLOT(contextAddTagToResource(KoResourceSP,QString))); - connect(&menu, SIGNAL(resourceTagRemovalRequested(KoResource*,QString)), - this, SLOT(contextRemoveTagFromResource(KoResource*,QString))); + connect(&menu, SIGNAL(resourceTagRemovalRequested(KoResourceSP,QString)), + this, SLOT(contextRemoveTagFromResource(KoResourceSP,QString))); - connect(&menu, SIGNAL(resourceAssignmentToNewTagRequested(KoResource*,QString)), - this, SLOT(contextCreateNewTag(KoResource*,QString))); + connect(&menu, SIGNAL(resourceAssignmentToNewTagRequested(KoResourceSP,QString)), + this, SLOT(contextCreateNewTag(KoResourceSP,QString))); menu.exec(pos); } -void KoResourceTaggingManager::contextMenuRequested(KoResource* currentResource, QPoint pos) +void KoResourceTaggingManager::contextMenuRequested(KoResourceSP currentResource, QPoint pos) { if (currentResource) { contextMenuRequested(currentResource, d->model->assignedTagsList(currentResource), pos); } } KoTagChooserWidget* KoResourceTaggingManager::tagChooserWidget() { return d->tagChooser; } QLineEdit* KoResourceTaggingManager::searchField() { return d->tagFilter->searchField(); } KoTagFilterWidget* KoResourceTaggingManager::tagFilterWidget() { return d->tagFilter; } diff --git a/libs/widgets/KoResourceTaggingManager.h b/libs/widgets/KoResourceTaggingManager.h index 2b965a2acb..9f668a26ef 100644 --- a/libs/widgets/KoResourceTaggingManager.h +++ b/libs/widgets/KoResourceTaggingManager.h @@ -1,94 +1,96 @@ /* * This file is part of the KDE project * Copyright (c) 2002 Patrick Julien * Copyright (c) 2007 Jan Hambrecht * Copyright (c) 2007 Sven Langkamp * Copyright (C) 2011 Srikanth Tiyyagura * Copyright (c) 2011 José Luis Vergara * Copyright (c) 2013 Sascha Suelzer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KORESOURCETAGGINGMANAGER_H #define KORESOURCETAGGINGMANAGER_H #include +#include + class QWidget; class QStringList; class QString; class QPoint; class KoTagFilterWidget; class KoTagChooserWidget; class KoLegacyResourceModel; -class KoResource; + /** * @brief The KoResourceTaggingManager class is ... * * XXX: this needs to be documented! */ class KoResourceTaggingManager : public QObject { Q_OBJECT public: explicit KoResourceTaggingManager(KoLegacyResourceModel* model, QWidget* parent); ~KoResourceTaggingManager() override; void showTaggingBar(bool show); QStringList availableTags() const; - void contextMenuRequested(KoResource* currentResource, QPoint pos); + void contextMenuRequested(KoResourceSP currentResource, QPoint pos); void allowTagModification( bool set ); bool allowTagModification(); KoTagFilterWidget* tagFilterWidget(); KoTagChooserWidget* tagChooserWidget(); class QLineEdit* searchField(); Q_SIGNALS: void updateView(); private Q_SLOTS: void undeleteTag(const QString& tagToUndelete); void purgeTagUndeleteList(); - void contextCreateNewTag(KoResource* resource, const QString& tag); + void contextCreateNewTag(KoResourceSP resource, const QString& tag); void contextCreateNewTag(const QString& tag); void syncTagBoxEntryRemoval(const QString& tag); void syncTagBoxEntryAddition(const QString& tag); void syncTagBoxEntries(); void tagSaveButtonPressed(); - void contextRemoveTagFromResource(KoResource* resource, const QString& tag); - void contextAddTagToResource(KoResource* resource, const QString& tag); + void contextRemoveTagFromResource(KoResourceSP resource, const QString& tag); + void contextAddTagToResource(KoResourceSP resource, const QString& tag); void renameTag(const QString &oldName, const QString &newName); void tagChooserIndexChanged(const QString& lineEditText); void tagSearchLineEditTextChanged(const QString& lineEditText); void removeTagFromComboBox(const QString& tag); private: - void contextMenuRequested(KoResource* resource, const QStringList& resourceTags, const QPoint& pos); + void contextMenuRequested(KoResourceSP resource, const QStringList& resourceTags, const QPoint& pos); void enableContextMenu(bool enable); - void removeResourceTag(KoResource* resource, const QString& tagName); - void addResourceTag(KoResource* resource, const QString& tagName); + void removeResourceTag(KoResourceSP resource, const QString& tagName); + void addResourceTag(KoResourceSP resource, const QString& tagName); void updateTaggedResourceView(); class Private; Private* const d; }; #endif // KORESOURCETAGGINGINTERFACE_H diff --git a/libs/widgets/kis_palette_view.cpp b/libs/widgets/kis_palette_view.cpp index 3c197a54ee..04ae9f9854 100644 --- a/libs/widgets/kis_palette_view.cpp +++ b/libs/widgets/kis_palette_view.cpp @@ -1,294 +1,294 @@ /* * Copyright (c) 2016 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_palette_view.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisPaletteDelegate.h" #include "KisPaletteModel.h" #include "kis_color_button.h" #include int KisPaletteView::MININUM_ROW_HEIGHT = 10; struct KisPaletteView::Private { QPointer model; bool allowPaletteModification {false}; // if modification is allowed from this widget }; KisPaletteView::KisPaletteView(QWidget *parent) : QTableView(parent) , m_d(new Private) { setItemDelegate(new KisPaletteDelegate(this)); setShowGrid(true); setDropIndicatorShown(true); setDragDropMode(QAbstractItemView::InternalMove); setSelectionMode(QAbstractItemView::SingleSelection); setDragEnabled(false); setAcceptDrops(false); /* * without this, a cycle might be created: * the view stretches to right border, and this make it need a scroll bar; * after the bar is added, the view shrinks to the bar, and this makes it * no longer need the bar any more, and the bar is removed again */ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); // set the size of swatches horizontalHeader()->setVisible(false); verticalHeader()->setVisible(false); horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); horizontalHeader()->setMinimumSectionSize(MININUM_ROW_HEIGHT); verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); verticalHeader()->setMinimumSectionSize(MININUM_ROW_HEIGHT); connect(horizontalHeader(), SIGNAL(sectionResized(int,int,int)), SLOT(slotHorizontalHeaderResized(int,int,int))); setAutoFillBackground(true); QScroller *scroller = KisKineticScroller::createPreconfiguredScroller(this); if (scroller) { connect(scroller, SIGNAL(stateChanged(QScroller::State)), this, SLOT(slotScrollerStateChanged(QScroller::State))); } } KisPaletteView::~KisPaletteView() { } void KisPaletteView::setCrossedKeyword(const QString &value) { KisPaletteDelegate *delegate = dynamic_cast(itemDelegate()); KIS_ASSERT_RECOVER_RETURN(delegate); delegate->setCrossedKeyword(value); } bool KisPaletteView::addEntryWithDialog(KoColor color) { QScopedPointer window(new KoDialog(this)); window->setWindowTitle(i18nc("@title:window", "Add a new Colorset Entry")); QFormLayout *editableItems = new QFormLayout(window.data()); window->mainWidget()->setLayout(editableItems); QComboBox *cmbGroups = new QComboBox(window.data()); QString defaultGroupName = i18nc("Name for default group", "Default"); cmbGroups->addItem(defaultGroupName); cmbGroups->addItems(m_d->model->colorSet()->getGroupNames()); QLineEdit *lnIDName = new QLineEdit(window.data()); QLineEdit *lnName = new QLineEdit(window.data()); KisColorButton *bnColor = new KisColorButton(window.data()); QCheckBox *chkSpot = new QCheckBox(window.data()); chkSpot->setToolTip(i18nc("@info:tooltip", "A spot color is a color that the printer is able to print without mixing the paints it has available to it. The opposite is called a process color.")); editableItems->addRow(i18n("Group"), cmbGroups); editableItems->addRow(i18n("ID"), lnIDName); editableItems->addRow(i18n("Name"), lnName); editableItems->addRow(i18n("Color"), bnColor); editableItems->addRow(i18nc("Spot color", "Spot"), chkSpot); cmbGroups->setCurrentIndex(0); lnName->setText(i18nc("Part of a default name for a color","Color")+" " + QString::number(m_d->model->colorSet()->colorCount()+1)); lnIDName->setText(QString::number(m_d->model->colorSet()->colorCount() + 1)); bnColor->setColor(color); chkSpot->setChecked(false); if (window->exec() == KoDialog::Accepted) { QString groupName = cmbGroups->currentText(); if (groupName == defaultGroupName) { groupName = QString(); } KisSwatch newEntry; newEntry.setColor(bnColor->color()); newEntry.setName(lnName->text()); newEntry.setId(lnIDName->text()); newEntry.setSpotColor(chkSpot->isChecked()); m_d->model->addEntry(newEntry, groupName); return true; } return false; } bool KisPaletteView::addGroupWithDialog() { KoDialog *window = new KoDialog(); window->setWindowTitle(i18nc("@title:window","Add a new group")); QFormLayout *editableItems = new QFormLayout(); window->mainWidget()->setLayout(editableItems); QLineEdit *lnName = new QLineEdit(); editableItems->addRow(i18nc("Name for a group", "Name"), lnName); lnName->setText(i18nc("Part of default name for a new group", "Color Group")+""+QString::number(m_d->model->colorSet()->getGroupNames().size()+1)); if (window->exec() == KoDialog::Accepted) { KisSwatchGroup group; group.setName(lnName->text()); m_d->model->addGroup(group); m_d->model->colorSet()->save(); return true; } return false; } bool KisPaletteView::removeEntryWithDialog(QModelIndex index) { bool keepColors = false; if (qvariant_cast(index.data(KisPaletteModel::IsGroupNameRole))) { QScopedPointer window(new KoDialog(this)); window->setWindowTitle(i18nc("@title:window","Removing Group")); QFormLayout *editableItems = new QFormLayout(window.data()); QCheckBox *chkKeep = new QCheckBox(window.data()); window->mainWidget()->setLayout(editableItems); editableItems->addRow(i18nc("Shows up when deleting a swatch group", "Keep the Colors"), chkKeep); if (window->exec() != KoDialog::Accepted) { return false; } keepColors = chkKeep->isChecked(); } m_d->model->removeEntry(index, keepColors); if (m_d->model->colorSet()->isGlobal()) { m_d->model->colorSet()->save(); } return true; } void KisPaletteView::selectClosestColor(const KoColor &color) { - KoColorSet* color_set = m_d->model->colorSet(); + KoColorSetSP color_set = m_d->model->colorSet(); if (!color_set) { return; } //also don't select if the color is the same as the current selection if (m_d->model->getEntry(currentIndex()).color() == color) { return; } selectionModel()->clearSelection(); QModelIndex index = m_d->model->indexForClosest(color); selectionModel()->setCurrentIndex(index, QItemSelectionModel::Select); } void KisPaletteView::slotFGColorChanged(const KoColor &color) { KConfigGroup group(KSharedConfig::openConfig(), ""); if (group.readEntry("colorsettings/forcepalettecolors", false)) { selectClosestColor(color); } } void KisPaletteView::setPaletteModel(KisPaletteModel *model) { if (m_d->model) { disconnect(m_d->model, Q_NULLPTR, this, Q_NULLPTR); } m_d->model = model; setModel(model); slotAdditionalGuiUpdate(); connect(model, SIGNAL(sigPaletteModified()), SLOT(slotAdditionalGuiUpdate())); connect(model, SIGNAL(sigPaletteChanged()), SLOT(slotAdditionalGuiUpdate())); connect(selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), SLOT(slotCurrentSelectionChanged(QModelIndex))); } KisPaletteModel* KisPaletteView::paletteModel() const { return m_d->model; } void KisPaletteView::setAllowModification(bool allow) { m_d->allowPaletteModification = allow; setDragEnabled(allow); setAcceptDrops(allow); } void KisPaletteView::slotHorizontalHeaderResized(int, int, int newSize) { resizeRows(newSize); slotAdditionalGuiUpdate(); } void KisPaletteView::resizeRows(int newSize) { verticalHeader()->setDefaultSectionSize(newSize); verticalHeader()->resizeSections(QHeaderView::Fixed); } void KisPaletteView::removeSelectedEntry() { if (selectedIndexes().size() <= 0) { return; } m_d->model->removeEntry(currentIndex()); } void KisPaletteView::slotAdditionalGuiUpdate() { clearSpans(); resizeRows(verticalHeader()->defaultSectionSize()); for (int groupNameRowNumber : m_d->model->m_rowGroupNameMap.keys()) { if (groupNameRowNumber == -1) { continue; } setSpan(groupNameRowNumber, 0, 1, m_d->model->columnCount()); setRowHeight(groupNameRowNumber, fontMetrics().lineSpacing() + 6); verticalHeader()->resizeSection(groupNameRowNumber, fontMetrics().lineSpacing() + 6); } } void KisPaletteView::slotCurrentSelectionChanged(const QModelIndex &newCurrent) { if (!newCurrent.isValid()) { return; } const bool isGroupName = newCurrent.data(KisPaletteModel::IsGroupNameRole).toBool(); const bool isCheckSlot = newCurrent.data(KisPaletteModel::CheckSlotRole).toBool(); const KisSwatch newEntry = m_d->model->getEntry(newCurrent); emit sigIndexSelected(newCurrent); if (isGroupName) { return; } if (isCheckSlot) { emit sigColorSelected(newEntry.color()); } } void KisPaletteView::setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer) { Q_ASSERT(m_d->model); m_d->model->setDisplayRenderer(displayRenderer); } diff --git a/libs/widgets/tests/KoResourceTaggingTest.cpp b/libs/widgets/tests/KoResourceTaggingTest.cpp index 3eb04e232e..b4e00ee165 100644 --- a/libs/widgets/tests/KoResourceTaggingTest.cpp +++ b/libs/widgets/tests/KoResourceTaggingTest.cpp @@ -1,170 +1,171 @@ /* * 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 "KoResourceTaggingTest.h" #include #include #include #include #include +#include #include "KoResourceServerProvider.h" #include "sdk/tests/kistest.h" void KoResourceTaggingTest::testInitialization() { // All Krita's resource types KoResourcePaths::addResourceType("gmic_definitions", "data", "/gmic/"); KoResourcePaths::addResourceType("icc_profiles", "data", "/color/icc"); KoResourcePaths::addResourceType("icc_profiles", "data", "/profiles/"); KoResourcePaths::addResourceType("kis_actions", "data", "/actions"); KoResourcePaths::addResourceType("brushes", "data", "/brushes/"); KoResourcePaths::addResourceType("kis_defaultpresets", "data", "/defaultpresets/"); KoResourcePaths::addResourceType("kis_images", "data", "/images/"); KoResourcePaths::addResourceType("paintoppresets", "data", "/paintoppresets/"); KoResourcePaths::addResourceType("kis_pics", "data", "/pics/"); KoResourcePaths::addResourceType("kis_resourcebundles", "data", "/bundles/"); KoResourcePaths::addResourceType("kis_shortcuts", "data", "/shortcuts/"); KoResourcePaths::addResourceType("kis_taskset", "data", "/taskset/"); KoResourcePaths::addResourceType("kis_taskset", "data", "/taskset/"); KoResourcePaths::addResourceType("windowlayouts", "data", "/windowlayouts/"); KoResourcePaths::addResourceType("workspaces", "data", "/workspaces/"); KoResourcePaths::addResourceType("ko_effects", "data", "/effects/"); KoResourcePaths::addResourceType("gradients", "data", "/gradients/"); KoResourcePaths::addResourceType("palettes", "data", "/palettes/"); KoResourcePaths::addResourceType("patterns", "data", "/patterns/"); KoResourcePaths::addResourceType("metadata_schema", "data", "/metadata/schemas/"); KoResourcePaths::addResourceType("psd_layer_style_collections", "data", "/asl"); KoResourcePaths::addResourceType("tags", "data", "/tags/"); KoResourceTagStore tagStore(KoResourceServerProvider::instance()->patternServer()); QVERIFY(tagStore.tagNamesList().isEmpty()); QVERIFY(tagStore.assignedTagsList(0).isEmpty()); QVERIFY(tagStore.searchTag("bla").isEmpty()); } void KoResourceTaggingTest::testTagging() { KoResourceServer* patServer = KoResourceServerProvider::instance()->patternServer(); KoResourceTagStore tagStore(patServer); - KoResource *res = patServer->resources().first(); + KoResourceSP res = patServer->resources().first(); QVERIFY(res); QVERIFY(patServer->resourceByFilename(res->shortFilename()) == res); tagStore.addTag(res, "test1"); QVERIFY(tagStore.tagNamesList().size() == 1); QStringList resources = tagStore.searchTag("test1"); QVERIFY(resources.size() == 1); - KoResource *res2 = patServer->resourceByFilename(resources.first()); + KoResourceSP res2 = patServer->resourceByFilename(resources.first()); QVERIFY(res == res2); tagStore.addTag(res, "test2"); QVERIFY(tagStore.tagNamesList().size() == 2); resources = tagStore.searchTag("test1"); QVERIFY(resources.size() == 1); res2 = patServer->resourceByFilename(resources.first()); QVERIFY(res == res2); tagStore.addTag(res, "test2"); QVERIFY(tagStore.tagNamesList().size() == 2); resources = tagStore.searchTag("test2"); QVERIFY(resources.size() == 1); res2 = patServer->resourceByFilename(resources.first()); QVERIFY(res == res2); resources = tagStore.searchTag("test1,test2"); QVERIFY(resources.size() == 1); res2 = patServer->resourceByFilename(resources.first()); QVERIFY(res == res2); tagStore.delTag(res, "test1"); QVERIFY(tagStore.tagNamesList().size() == 2); resources = tagStore.searchTag("test1"); QVERIFY(resources.size() == 0); resources = tagStore.searchTag("test2"); QVERIFY(resources.size() == 1); res2 = patServer->resourceByFilename(resources.first()); QVERIFY(res == res2); tagStore.delTag("test1"); QVERIFY(tagStore.tagNamesList().size() == 1); } void KoResourceTaggingTest::testReadWriteXML() { KoResourceServer* patServer = KoResourceServerProvider::instance()->patternServer(); KoResourceTagStore tagStore(patServer); - QList patterns = patServer->resources(); + QList patterns = patServer->resources(); Q_ASSERT(patterns.size() > 5); tagStore.addTag(patterns[0], "test0"); tagStore.addTag(patterns[1], "test1"); tagStore.addTag(patterns[2], "test2"); tagStore.addTag(patterns[2], "test2"); tagStore.addTag(patterns[2], "test1"); tagStore.addTag(patterns[3], "test3"); tagStore.addTag(patterns[4], "test4"); tagStore.addTag(patterns[5], "test5"); tagStore.addTag(patterns[5], "test5.1"); tagStore.addTag(patterns[5], "test5.2"); tagStore.addTag(0, "dummytest"); QVERIFY(tagStore.tagNamesList().size() == 9); tagStore.writeXMLFile(QString(FILES_OUTPUT_DIR) + "/" + "kis_pattern_tags.xml"); KoResourceTagStore tagStore2(patServer); tagStore2.readXMLFile(QString(FILES_OUTPUT_DIR) + "/" + "kis_pattern_tags.xml"); QVERIFY(tagStore2.tagNamesList().size() == 9); QStringList resources = tagStore2.searchTag("test0"); QVERIFY(resources.size() == 1); QVERIFY(patServer->resourceByFilename(resources[0]) == patterns[0]); resources = tagStore2.searchTag("test1"); QVERIFY(resources.size() == 2); resources = tagStore2.searchTag("test2"); QVERIFY(resources.size() == 1); resources = tagStore2.searchTag("test3"); QVERIFY(resources.size() == 1); resources = tagStore2.searchTag("test4"); QVERIFY(resources.size() == 1); resources = tagStore2.searchTag("test5"); QVERIFY(resources.size() == 1); resources = tagStore2.searchTag("test5.1"); QVERIFY(resources.size() == 1); resources = tagStore2.searchTag("test5.2"); QVERIFY(resources.size() == 1); resources = tagStore2.searchTag("dummytest"); QVERIFY(resources.size() == 0); } KISTEST_MAIN(KoResourceTaggingTest) diff --git a/plugins/dockers/advancedcolorselector/kis_color_selector.cpp b/plugins/dockers/advancedcolorselector/kis_color_selector.cpp index 7c646f5441..fb538c346b 100644 --- a/plugins/dockers/advancedcolorselector/kis_color_selector.cpp +++ b/plugins/dockers/advancedcolorselector/kis_color_selector.cpp @@ -1,395 +1,395 @@ /* * Copyright (c) 2010 Adam Celarek * * 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; version 2.1 of the License. * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_color_selector.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_color_selector_ring.h" #include "kis_color_selector_triangle.h" #include "kis_color_selector_simple.h" #include "kis_color_selector_wheel.h" #include "kis_color_selector_container.h" #include "kis_canvas2.h" #include "kis_signal_compressor.h" #include "KisViewManager.h" KisColorSelector::KisColorSelector(KisColorSelectorConfiguration conf, QWidget* parent) : KisColorSelectorBase(parent), m_ring(0), m_triangle(0), m_slider(0), m_square(0), m_wheel(0), m_mainComponent(0), m_subComponent(0), m_grabbingComponent(0), m_blipDisplay(true) { init(); updateSettings(); setConfiguration(conf); } KisColorSelector::KisColorSelector(QWidget* parent) : KisColorSelectorBase(parent), m_ring(0), m_triangle(0), m_slider(0), m_square(0), m_wheel(0), m_button(0), m_mainComponent(0), m_subComponent(0), m_grabbingComponent(0), m_blipDisplay(true) { init(); updateSettings(); } KisColorSelectorBase* KisColorSelector::createPopup() const { KisColorSelectorBase* popup = new KisColorSelector(0); popup->setColor(m_lastRealColor); return popup; } void KisColorSelector::setConfiguration(KisColorSelectorConfiguration conf) { m_configuration = conf; if(m_mainComponent!=0) { Q_ASSERT(m_subComponent!=0); m_mainComponent->setGeometry(0, 0, 0, 0); m_subComponent->setGeometry(0, 0, 0, 0); m_mainComponent->disconnect(); m_subComponent->disconnect(); } switch (m_configuration.mainType) { case KisColorSelectorConfiguration::Square: m_mainComponent=m_square; break; case KisColorSelectorConfiguration::Wheel: m_mainComponent=m_wheel; break; case KisColorSelectorConfiguration::Triangle: m_mainComponent=m_triangle; break; default: Q_ASSERT(false); } switch (m_configuration.subType) { case KisColorSelectorConfiguration::Ring: m_subComponent=m_ring; break; case KisColorSelectorConfiguration::Slider: m_subComponent=m_slider; break; default: Q_ASSERT(false); } connect(m_mainComponent, SIGNAL(paramChanged(qreal,qreal,qreal,qreal,qreal,qreal,qreal,qreal,qreal)), m_subComponent, SLOT(setParam(qreal,qreal,qreal,qreal,qreal,qreal,qreal,qreal,qreal)), Qt::UniqueConnection); connect(m_subComponent, SIGNAL(paramChanged(qreal,qreal,qreal,qreal,qreal,qreal,qreal,qreal,qreal)), m_mainComponent, SLOT(setParam(qreal,qreal,qreal,qreal,qreal,qreal,qreal,qreal,qreal)), Qt::UniqueConnection); connect(m_mainComponent, SIGNAL(update()), m_signalCompressor, SLOT(start()), Qt::UniqueConnection); connect(m_subComponent, SIGNAL(update()), m_signalCompressor, SLOT(start()), Qt::UniqueConnection); m_mainComponent->setConfiguration(m_configuration.mainTypeParameter, m_configuration.mainType); m_subComponent->setConfiguration(m_configuration.subTypeParameter, m_configuration.subType); QResizeEvent event(QSize(width(), height()), QSize()); resizeEvent(&event); } KisColorSelectorConfiguration KisColorSelector::configuration() const { return m_configuration; } void KisColorSelector::updateSettings() { KisColorSelectorBase::updateSettings(); KConfigGroup cfg = KSharedConfig::openConfig()->group("advancedColorSelector"); setConfiguration(KisColorSelectorConfiguration::fromString(cfg.readEntry("colorSelectorConfiguration", KisColorSelectorConfiguration().toString()))); } -void KisColorSelector::slotGamutMaskSet(KoGamutMask *gamutMask) +void KisColorSelector::slotGamutMaskSet(KoGamutMaskSP gamutMask) { m_mainComponent->setGamutMask(gamutMask); m_subComponent->setGamutMask(gamutMask); slotGamutMaskToggle(true); } void KisColorSelector::slotGamutMaskUnset() { m_mainComponent->unsetGamutMask(); m_subComponent->unsetGamutMask(); slotGamutMaskToggle(false); } void KisColorSelector::slotGamutMaskPreviewUpdate() { m_mainComponent->updateGamutMaskPreview(); m_subComponent->updateGamutMaskPreview(); } void KisColorSelector::slotGamutMaskToggle(bool state) { m_mainComponent->toggleGamutMask(state); m_subComponent->toggleGamutMask(state); } void KisColorSelector::updateIcons() { if (m_button) { m_button->setIcon(KisIconUtils::loadIcon("configure")); } } void KisColorSelector::hasAtLeastOneDocument(bool value) { m_hasAtLeastOneDocumentOpen = value; } void KisColorSelector::reset() { KisColorSelectorBase::reset(); if (m_mainComponent) { m_mainComponent->setDirty(); } if (m_subComponent) { m_subComponent->setDirty(); } } void KisColorSelector::paintEvent(QPaintEvent* e) { Q_UNUSED(e); QPainter p(this); p.fillRect(0,0,width(), height(), QColor(128,128,128)); p.setRenderHint(QPainter::Antialiasing); // this variable name isn't entirely accurate to what always happens. see definition in header file to understand it better if (!m_hasAtLeastOneDocumentOpen) { p.setOpacity(0.2); } m_mainComponent->paintEvent(&p); m_subComponent->paintEvent(&p); p.setOpacity(1.0); } inline int iconSize(qreal width, qreal height) { qreal radius = qMin(width, height)/2.; qreal xm = width/2.; qreal ym = height/2.; if(xm>=2*ym || ym>=2*xm) return qBound(5., radius, 32.); qreal a=-2; qreal b=2.*(xm+ym); qreal c=radius*radius-xm*xm-ym*ym; return qBound(5., ((-b+sqrt(b*b-4*a*c))/(2*a)), 32.); } void KisColorSelector::resizeEvent(QResizeEvent* e) { if (m_configuration.subType == KisColorSelectorConfiguration::Ring) { m_ring->setGeometry(0,0,width(), height()); if (displaySettingsButton()) { int size = iconSize(width(), height()); m_button->setGeometry(0, 0, size, size); } if (m_configuration.mainType == KisColorSelectorConfiguration::Triangle) { m_triangle->setGeometry(width()/2-m_ring->innerRadius(), height()/2-m_ring->innerRadius(), m_ring->innerRadius()*2, m_ring->innerRadius()*2); } else { int size = m_ring->innerRadius()*2/sqrt(2.); m_square->setGeometry(width()/2-size/2, height()/2-size/2, size, size); } } else { // type wheel and square if (m_configuration.mainType == KisColorSelectorConfiguration::Wheel) { if(displaySettingsButton()) { int size = iconSize(width(), height()*0.9); m_button->setGeometry(0, height()*0.1, size, size); } m_mainComponent->setGeometry(0, height()*0.1, width(), height()*0.9); m_subComponent->setGeometry( 0, 0, width(), height()*0.1); } else { int buttonSize = 0; if(displaySettingsButton()) { buttonSize = qBound(20, int(0.1*height()), 32); m_button->setGeometry(0, 0, buttonSize, buttonSize); } if(height()>width()) { int selectorHeight=height()-buttonSize; m_mainComponent->setGeometry(0, buttonSize+selectorHeight*0.1, width(), selectorHeight*0.9); m_subComponent->setGeometry( 0, buttonSize, width(), selectorHeight*0.1); } else { int selectorWidth=width()-buttonSize; m_mainComponent->setGeometry(buttonSize, height()*0.1, selectorWidth, height()*0.9); m_subComponent->setGeometry( buttonSize, 0, selectorWidth, height()*0.1); } } } // reset the correct color after resizing the widget setColor(m_lastRealColor); KisColorSelectorBase::resizeEvent(e); } void KisColorSelector::mousePressEvent(QMouseEvent* e) { e->setAccepted(false); KisColorSelectorBase::mousePressEvent(e); if(!e->isAccepted()) { if(m_mainComponent->wantsGrab(e->x(), e->y())) m_grabbingComponent=m_mainComponent; else if(m_subComponent->wantsGrab(e->x(), e->y())) m_grabbingComponent=m_subComponent; mouseEvent(e); updatePreviousColorPreview(); e->accept(); } } void KisColorSelector::mouseMoveEvent(QMouseEvent* e) { KisColorSelectorBase::mouseMoveEvent(e); mouseEvent(e); e->accept(); } void KisColorSelector::mouseReleaseEvent(QMouseEvent* e) { e->setAccepted(false); KisColorSelectorBase::mouseReleaseEvent(e); if(!e->isAccepted() && !(m_lastRealColor == m_currentRealColor)) { m_lastRealColor = m_currentRealColor; m_lastColorRole = Acs::buttonToRole(e->button()); updateColor(m_lastRealColor, m_lastColorRole, false); updateBaseColorPreview(m_currentRealColor); e->accept(); } m_grabbingComponent=0; } bool KisColorSelector::displaySettingsButton() { return dynamic_cast(parent()); } void KisColorSelector::setColor(const KoColor &color) { m_mainComponent->setColor(color); m_subComponent->setColor(color); m_lastRealColor = color; m_signalCompressor->start(); } void KisColorSelector::mouseEvent(QMouseEvent *e) { if (m_grabbingComponent && (e->buttons() & Qt::LeftButton || e->buttons() & Qt::RightButton)) { m_grabbingComponent->mouseEvent(e->x(), e->y()); KoColor color = m_mainComponent->currentColor(); Acs::ColorRole role = Acs::buttonsToRole(e->button(), e->buttons()); m_currentRealColor = color; requestUpdateColorAndPreview(color, role); } } void KisColorSelector::init() { setAcceptDrops(true); m_lastColorRole = Acs::Foreground; m_ring = new KisColorSelectorRing(this); m_triangle = new KisColorSelectorTriangle(this); m_slider = new KisColorSelectorSimple(this); m_square = new KisColorSelectorSimple(this); m_wheel = new KisColorSelectorWheel(this); if(displaySettingsButton()) { m_button = new QPushButton(this); m_button->setIcon(KisIconUtils::loadIcon("configure")); m_button->setFlat(true); connect(m_button, SIGNAL(clicked()), SIGNAL(settingsButtonClicked())); } // a tablet can send many more signals, than a mouse // this causes many repaints, if updating after every signal. m_signalCompressor = new KisSignalCompressor(20, KisSignalCompressor::FIRST_INACTIVE, this); connect(m_signalCompressor, SIGNAL(timeout()), SLOT(update())); setMinimumSize(40, 40); } diff --git a/plugins/dockers/advancedcolorselector/kis_color_selector.h b/plugins/dockers/advancedcolorselector/kis_color_selector.h index ef0f68ec7b..b9053e6b22 100644 --- a/plugins/dockers/advancedcolorselector/kis_color_selector.h +++ b/plugins/dockers/advancedcolorselector/kis_color_selector.h @@ -1,104 +1,105 @@ /* * Copyright (c) 2010 Adam Celarek * * 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; version 2.1 of the License. * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_COLOR_SELECTOR_H #define KIS_COLOR_SELECTOR_H #include "kis_color_selector_base.h" #include +#include class KisColorSelectorRing; class KisColorSelectorComponent; class KisColorSelectorSimple; class KisColorSelectorWheel; class QPushButton; class KisSignalCompressor; class KisColorSelector : public KisColorSelectorBase { Q_OBJECT public: KisColorSelector(KisColorSelectorConfiguration conf, QWidget* parent = 0); KisColorSelector(QWidget* parent=0); KisColorSelectorBase* createPopup() const override; void setConfiguration(KisColorSelectorConfiguration conf); KisColorSelectorConfiguration configuration() const; void setColor(const KoColor &color) override; /// update icons when a theme update happens void updateIcons(); void hasAtLeastOneDocument(bool value); public Q_SLOTS: void reset() override; void updateSettings() override; - void slotGamutMaskSet(KoGamutMask* gamutMask); + void slotGamutMaskSet(KoGamutMaskSP gamutMask); void slotGamutMaskUnset(); void slotGamutMaskPreviewUpdate(); void slotGamutMaskToggle(bool state); Q_SIGNALS: void settingsButtonClicked(); protected: void paintEvent(QPaintEvent*) override; void resizeEvent(QResizeEvent*) override; void mousePressEvent(QMouseEvent*) override; void mouseMoveEvent(QMouseEvent*) override; void mouseReleaseEvent(QMouseEvent*) override; bool displaySettingsButton(); private: void mouseEvent(QMouseEvent* e); void init(); KisColorSelectorRing* m_ring; KisColorSelectorComponent* m_triangle; KisColorSelectorSimple* m_slider; KisColorSelectorSimple* m_square; KisColorSelectorWheel* m_wheel; QPushButton* m_button; KisColorSelectorComponent* m_mainComponent; KisColorSelectorComponent* m_subComponent; KisColorSelectorComponent* m_grabbingComponent; KisSignalCompressor *m_signalCompressor; KisColorSelectorConfiguration m_configuration; KoColor m_lastRealColor; KoColor m_currentRealColor; bool m_blipDisplay; Acs::ColorRole m_lastColorRole; /// if Krita starts with a reference to this component that is attached to a canvas, it will call setCanvas() /// that check will be what ultimately decides whether this component will look enabled or disabled /// This color selector is sometimes not attached to the canvas, so we shouldn't disable it in that situation /// One instance of that is when you select the color wheel type from the settings. bool m_hasAtLeastOneDocumentOpen = true; public: void setDisplayBlip(bool disp) {m_blipDisplay = disp;} bool displayBlip() const {return m_blipDisplay;} }; #endif // KIS_COLSELNG_COLOR_SELECTOR_H diff --git a/plugins/dockers/advancedcolorselector/kis_color_selector_component.cpp b/plugins/dockers/advancedcolorselector/kis_color_selector_component.cpp index bdca98a0f0..e759bd56f9 100644 --- a/plugins/dockers/advancedcolorselector/kis_color_selector_component.cpp +++ b/plugins/dockers/advancedcolorselector/kis_color_selector_component.cpp @@ -1,240 +1,240 @@ /* * Copyright (c) 2010 Adam Celarek * * 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 */ #include "kis_color_selector_component.h" #include "kis_color_selector_base.h" #include "KoColorSpace.h" #include #include #include KisColorSelectorComponent::KisColorSelectorComponent(KisColorSelector* parent) : QObject(parent), m_hue(0), m_hsvSaturation(1), m_value(1), m_hslSaturation(1), m_lightness(0.5), m_hsiSaturation(1), m_intensity(0.333), m_hsySaturation(1), m_luma(0.299), m_parent(parent), m_gamutMaskOn(false), m_currentGamutMask(nullptr), m_maskPreviewActive(true), m_lastX(0), m_lastY(0), m_x(0), m_y(0), m_width(0), m_height(0), m_dirty(true), m_lastColorSpace(0) { Q_ASSERT(parent); } void KisColorSelectorComponent::setGeometry(int x, int y, int width, int height) { m_x=x; m_y=y; m_width=width; m_height=height; m_dirty=true; } void KisColorSelectorComponent::paintEvent(QPainter* painter) { painter->save(); painter->translate(m_x, m_y); paint(painter); painter->restore(); m_dirty=false; m_lastColorSpace=colorSpace(); } void KisColorSelectorComponent::mouseEvent(int x, int y) { int newX=qBound(0, (x-m_x), width()); int newY=qBound(0, (y-m_y), height()); selectColor(newX, newY); m_lastX=newX; m_lastY=newY; } const KoColorSpace* KisColorSelectorComponent::colorSpace() const { const KoColorSpace* cs = m_parent->colorSpace(); Q_ASSERT(cs); return cs; } void KisColorSelectorComponent::setDirty() { m_dirty = true; } -void KisColorSelectorComponent::setGamutMask(KoGamutMask *gamutMask) +void KisColorSelectorComponent::setGamutMask(KoGamutMaskSP gamutMask) { m_currentGamutMask = gamutMask; m_gamutMaskOn = true; } void KisColorSelectorComponent::unsetGamutMask() { m_gamutMaskOn = false; m_currentGamutMask = nullptr; } void KisColorSelectorComponent::updateGamutMaskPreview() { setDirty(); update(); } void KisColorSelectorComponent::toggleGamutMask(bool state) { m_gamutMaskOn = state; setDirty(); update(); } bool KisColorSelectorComponent::isDirty() const { return m_dirty || m_lastColorSpace!=colorSpace(); } bool KisColorSelectorComponent::containsPointInComponentCoords(int x, int y) const { if(x>=0 && y>=0 && x<=width() && y<=height()) return true; else return false; } KoColor KisColorSelectorComponent::currentColor() { return selectColor(m_lastX, m_lastY); } void KisColorSelectorComponent::setParam(qreal hue, qreal hsvSaturation, qreal value, qreal hslSaturation, qreal lightness, qreal hsiSaturation, qreal intensity, qreal hsySaturation, qreal luma) { if(qFuzzyCompare(m_hue, hue) && qFuzzyCompare(m_hsvSaturation, hsvSaturation) && qFuzzyCompare(m_value, value) && qFuzzyCompare(m_hslSaturation, hslSaturation) && qFuzzyCompare(m_lightness, lightness) && qFuzzyCompare(m_hsiSaturation, hsiSaturation) && qFuzzyCompare(m_intensity, intensity) && qFuzzyCompare(m_hsySaturation, hsySaturation) && qFuzzyCompare(m_luma, luma)) return; if(hue>=0. && hue<=1.) m_hue=hue; if(hsvSaturation>=0. && hsvSaturation<=1.) { m_hsvSaturation=hsvSaturation; m_hslSaturation=-1; m_hsiSaturation=-1; m_hsySaturation=-1; } if(value>=0. && value<=1.) { m_value=value; m_intensity=-1; m_luma=-1; m_lightness=-1; } if(hslSaturation>=0. && hslSaturation<=1.) { m_hslSaturation=hslSaturation; m_hsvSaturation=-1; m_hsiSaturation=-1; m_hsySaturation=-1; } if(lightness>=0. && lightness<=1.) { m_lightness=lightness; m_value=-1; m_luma=-1; m_intensity=-1; } if(hsiSaturation>=0. && hsiSaturation<=1.) { m_hsiSaturation=hsiSaturation; m_hsvSaturation=-1; m_hslSaturation=-1; m_hsySaturation=-1; } if(intensity>=0. && intensity<=1.) { m_intensity=intensity; m_value=-1; m_luma=-1; m_lightness=-1; } if(hsySaturation>=0. && hsySaturation<=1.) { m_hsySaturation=hsySaturation; m_hsvSaturation=-1; m_hsiSaturation=-1; m_hslSaturation=-1; } if(luma>=0. && luma<=1.) { m_intensity=-1; m_value=-1; m_luma=luma; m_lightness=-1; } m_dirty=true; emit update(); } int KisColorSelectorComponent::width() const { return m_width; } int KisColorSelectorComponent::height() const { return m_height; } void KisColorSelectorComponent::setConfiguration(Parameter param, Type type) { m_parameter = param; m_type = type; } void KisColorSelectorComponent::setLastMousePosition(int x, int y) { // prevent movement due to rounding errors if (abs((int)m_lastX - x) > 1 || abs((int)m_lastY - y) > 1) { m_lastX = x; m_lastY = y; } } diff --git a/plugins/dockers/advancedcolorselector/kis_color_selector_component.h b/plugins/dockers/advancedcolorselector/kis_color_selector_component.h index 6e3c67a710..00e3cbd611 100644 --- a/plugins/dockers/advancedcolorselector/kis_color_selector_component.h +++ b/plugins/dockers/advancedcolorselector/kis_color_selector_component.h @@ -1,125 +1,125 @@ /* * Copyright (c) 2010 Adam Celarek * * 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 */ #ifndef KIS_COLOR_SELECTOR_COMPONENT_H #define KIS_COLOR_SELECTOR_COMPONENT_H #include #include #include #include "kis_color_selector.h" class KoColorSpace; class QPainter; class KisColorSelectorComponent : public QObject { Q_OBJECT public: typedef KisColorSelectorConfiguration::Parameters Parameter; typedef KisColorSelectorConfiguration::Type Type; explicit KisColorSelectorComponent(KisColorSelector* parent); void setGeometry(int x, int y, int width, int height); void paintEvent(QPainter*); /// saves the mouse position, so that a blip can be created. virtual void mouseEvent(int x, int y); /// return the color, that was selected by calling mouseEvent KoColor currentColor(); int width() const; int height() const; /// setConfiguration can be ignored (for instance ring and triangle, as they can have only one config) void setConfiguration(Parameter param, Type type); /// set the color, blibs etc virtual void setColor(const KoColor& color) = 0; /// force subsequent redraw of the component void setDirty(); /// returns true, if this component wants to grab the mouse (normally true, if containsPoint returns true) bool wantsGrab(int x, int y) {return containsPointInComponentCoords(x-m_x, y-m_y);} - void setGamutMask(KoGamutMask* gamutMask); + void setGamutMask(KoGamutMaskSP gamutMask); void unsetGamutMask(); void updateGamutMaskPreview(); void toggleGamutMask(bool state); public Q_SLOTS: /// set hue, saturation, value or/and lightness /// unused parameters should be set to -1 void setParam(qreal hue, qreal hsvSaturation, qreal value, qreal hslSaturation, qreal lightness, qreal hsiSaturation, qreal intensity, qreal hsySaturation, qreal luma); Q_SIGNALS: /// request for repaint, for instance, if the hue changes. void update(); /// -1, if unaffected void paramChanged(qreal hue, qreal hsvSaturation, qreal value, qreal hslSaturation, qreal lightness, qreal hsiSaturation, qreal intensity, qreal hsySaturation, qreal luma); protected: const KoColorSpace* colorSpace() const; /// returns true, if ether the colour space, the size or the parameters have changed since the last paint event bool isDirty() const; /// this method must be overloaded to return the colour at position x/y and draw a marker on that position virtual KoColor selectColor(int x, int y) = 0; /// paint component using given painter /// the component should respect width() and height() (eg. scale to width and height), but doesn't /// have to care about x/y coordinates (top left corner) virtual void paint(QPainter*) = 0; /// a subclass can implement this method, the default returns true if the coordinates are in the component rect /// values for the subclasses are provided in component coordinates, eg (0,0) is top left of component virtual bool containsPointInComponentCoords(int x, int y) const; // Workaround for Bug 287001 void setLastMousePosition(int x, int y); qreal m_hue; qreal m_hsvSaturation; qreal m_value; qreal m_hslSaturation; qreal m_lightness; qreal m_hsiSaturation; qreal m_intensity; qreal m_hsySaturation; qreal m_luma; Parameter m_parameter; Type m_type; KisColorSelector* m_parent; bool m_gamutMaskOn; - KoGamutMask* m_currentGamutMask; + KoGamutMaskSP m_currentGamutMask; bool m_maskPreviewActive; qreal m_lastX; qreal m_lastY; int m_x; int m_y; private: int m_width; int m_height; bool m_dirty; const KoColorSpace* m_lastColorSpace; }; #endif // KIS_COLOR_SELECTOR_COMPONENT_H diff --git a/plugins/dockers/advancedcolorselector/kis_color_selector_container.cpp b/plugins/dockers/advancedcolorselector/kis_color_selector_container.cpp index 6a4fc834d7..1f90eae7e0 100644 --- a/plugins/dockers/advancedcolorselector/kis_color_selector_container.cpp +++ b/plugins/dockers/advancedcolorselector/kis_color_selector_container.cpp @@ -1,244 +1,244 @@ /* * Copyright (c) 2010 Adam Celarek * * 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 */ #include "kis_color_selector_container.h" #include "kis_color_selector.h" #include "kis_my_paint_shade_selector.h" #include "kis_minimal_shade_selector.h" #include #include #include #include #include #include #include #include #include #include #include "KisViewManager.h" #include "kis_canvas2.h" #include "kis_canvas_resource_provider.h" #include "kis_node_manager.h" #include "kis_node.h" #include "kis_paint_device.h" #include "kis_action_registry.h" KisColorSelectorContainer::KisColorSelectorContainer(QWidget *parent) : QWidget(parent), m_colorSelector(new KisColorSelector(this)), m_myPaintShadeSelector(new KisMyPaintShadeSelector(this)), m_minimalShadeSelector(new KisMinimalShadeSelector(this)), m_shadeSelector(m_myPaintShadeSelector), m_gamutMaskToolbar(new KisGamutMaskToolbar(this)), m_canvas(0) { m_widgetLayout = new QBoxLayout(QBoxLayout::TopToBottom, this); m_widgetLayout->setSpacing(0); m_widgetLayout->setMargin(0); m_gamutMaskToolbar->setContentsMargins(0, 0, 0, 5); m_gamutMaskToolbar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); m_colorSelector->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_myPaintShadeSelector->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_minimalShadeSelector->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_widgetLayout->addWidget(m_gamutMaskToolbar); m_widgetLayout->addWidget(m_colorSelector); m_widgetLayout->addWidget(m_myPaintShadeSelector); m_widgetLayout->addWidget(m_minimalShadeSelector); m_gamutMaskToolbar->hide(); m_myPaintShadeSelector->hide(); m_minimalShadeSelector->hide(); connect(m_colorSelector,SIGNAL(settingsButtonClicked()), SIGNAL(openSettings())); connect(this, SIGNAL(settingsChanged()), m_colorSelector, SLOT(updateSettings())); connect(this, SIGNAL(settingsChanged()), m_myPaintShadeSelector, SLOT(updateSettings())); connect(this, SIGNAL(settingsChanged()), this, SLOT(updateSettings())); connect(this, SIGNAL(settingsChanged()), m_minimalShadeSelector, SLOT(updateSettings())); m_colorSelAction = KisActionRegistry::instance()->makeQAction("show_color_selector", this); connect(m_colorSelAction, SIGNAL(triggered()), m_colorSelector, SLOT(showPopup()), Qt::UniqueConnection); m_mypaintAction = KisActionRegistry::instance()->makeQAction("show_mypaint_shade_selector", this); connect(m_mypaintAction, SIGNAL(triggered()), m_myPaintShadeSelector, SLOT(showPopup()), Qt::UniqueConnection); m_minimalAction = KisActionRegistry::instance()->makeQAction("show_minimal_shade_selector", this); connect(m_minimalAction, SIGNAL(triggered()), m_minimalShadeSelector, SLOT(showPopup()), Qt::UniqueConnection); } void KisColorSelectorContainer::unsetCanvas() { m_colorSelector->hasAtLeastOneDocument(doesAtleastOneDocumentExist()); m_colorSelector->unsetCanvas(); m_myPaintShadeSelector->unsetCanvas(); m_minimalShadeSelector->unsetCanvas(); m_canvas = 0; } bool KisColorSelectorContainer::doesAtleastOneDocumentExist() { if (m_canvas && m_canvas->viewManager() && m_canvas->viewManager()->document() ) { if (m_canvas->viewManager()->document()->image()->height() == 0) { return false; } else { return true; } } else { return false; } } void KisColorSelectorContainer::slotUpdateIcons() { m_colorSelector->updateIcons(); } void KisColorSelectorContainer::setCanvas(KisCanvas2* canvas) { if (m_canvas) { m_canvas->disconnectCanvasObserver(this); m_canvas->viewManager()->nodeManager()->disconnect(this); KActionCollection *ac = m_canvas->viewManager()->actionCollection(); ac->takeAction(ac->action("show_color_selector")); ac->takeAction(ac->action("show_mypaint_shade_selector")); ac->takeAction(ac->action("show_minimal_shade_selector")); } m_canvas = canvas; m_colorSelector->setCanvas(canvas); m_myPaintShadeSelector->setCanvas(canvas); m_minimalShadeSelector->setCanvas(canvas); m_colorSelector->hasAtLeastOneDocument(doesAtleastOneDocumentExist()); if (m_canvas && m_canvas->viewManager()) { if (m_canvas->viewManager()->nodeManager()) { connect(m_canvas->viewManager()->nodeManager(), SIGNAL(sigLayerActivated(KisLayerSP)), SLOT(reactOnLayerChange()), Qt::UniqueConnection); } - connect(m_canvas->viewManager()->resourceProvider(), SIGNAL(sigGamutMaskChanged(KoGamutMask*)), - m_colorSelector, SLOT(slotGamutMaskSet(KoGamutMask*))); + connect(m_canvas->viewManager()->resourceProvider(), SIGNAL(sigGamutMaskChanged(KoGamutMaskSP)), + m_colorSelector, SLOT(slotGamutMaskSet(KoGamutMaskSP))); connect(m_canvas->viewManager()->resourceProvider(), SIGNAL(sigGamutMaskUnset()), m_colorSelector, SLOT(slotGamutMaskUnset())); connect(m_canvas->viewManager()->resourceProvider(), SIGNAL(sigGamutMaskPreviewUpdate()), m_colorSelector, SLOT(slotGamutMaskPreviewUpdate())); m_gamutMaskToolbar->connectMaskSignals(m_canvas->viewManager()->resourceProvider()); // gamut mask connections connect(m_gamutMaskToolbar, SIGNAL(sigGamutMaskToggle(bool)), m_colorSelector, SLOT(slotGamutMaskToggle(bool))); KActionCollection* actionCollection = canvas->viewManager()->actionCollection(); actionCollection->addAction("show_color_selector", m_colorSelAction); actionCollection->addAction("show_mypaint_shade_selector", m_mypaintAction); actionCollection->addAction("show_minimal_shade_selector", m_minimalAction); } } void KisColorSelectorContainer::updateSettings() { KConfigGroup cfg = KSharedConfig::openConfig()->group("advancedColorSelector"); m_onDockerResizeSetting = (int)cfg.readEntry("onDockerResize", 0); QString type = cfg.readEntry("shadeSelectorType", "Minimal"); QWidget* newShadeSelector; if(type=="MyPaint") newShadeSelector = m_myPaintShadeSelector; else if (type=="Minimal") newShadeSelector = m_minimalShadeSelector; else newShadeSelector = 0; if(m_shadeSelector!=newShadeSelector && m_shadeSelector!=0) { m_shadeSelector->hide(); } m_shadeSelector=newShadeSelector; if(m_shadeSelector!=0) m_shadeSelector->show(); if (m_colorSelector->configuration().mainType == KisColorSelectorConfiguration::Wheel) { m_gamutMaskToolbar->show(); } else { m_gamutMaskToolbar->hide(); } } void KisColorSelectorContainer::reactOnLayerChange() { if (m_canvas) { KisNodeSP node = m_canvas->viewManager()->resourceProvider()->currentNode(); if (node) { KisPaintDeviceSP device = node->paintDevice(); if (device) { m_colorSelAction->setEnabled(true); m_mypaintAction->setEnabled(true); m_minimalAction->setEnabled(true); } else { // m_colorSelAction->setEnabled(false); // m_mypaintAction->setEnabled(false); // m_minimalAction->setEnabled(false); } } } } void KisColorSelectorContainer::resizeEvent(QResizeEvent * e) { if(m_shadeSelector!=0) { int minimumHeightForBothWidgets = m_colorSelector->minimumHeight()+m_shadeSelector->minimumHeight()+30; //+30 for the buttons (temporarily) if(height()hide(); } else { m_shadeSelector->show(); } // m_onDockerResizeSetting==0 is allow horizontal layout if(height() < width() && m_onDockerResizeSetting==0 && m_shadeSelector!=m_minimalShadeSelector) { m_widgetLayout->setDirection(QBoxLayout::LeftToRight); } else { m_widgetLayout->setDirection(QBoxLayout::TopToBottom); } } QWidget::resizeEvent(e); } diff --git a/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.cpp b/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.cpp index 22b0e01c31..8357e546b6 100644 --- a/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.cpp +++ b/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.cpp @@ -1,459 +1,459 @@ /* * Copyright (c) 2009 Cyrille Berger * * 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; version 2.1 of the License. * * 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 program; 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "artisticcolorselector_dock.h" #include #include #include #include #include "ui_wdgArtisticColorSelector.h" #include "ui_wdgARCSSettings.h" #include "ui_wdgWheelPreferencesPopup.h" class KisMainWindow; struct ArtisticColorSelectorUI: public QWidget, public Ui_wdgArtisticColorSelector { ArtisticColorSelectorUI() { setupUi(this); } }; struct ARCSSettingsUI: public QWidget, public Ui_wdgARCSSettings { ARCSSettingsUI() { setupUi(this); } }; struct WheelPreferencesPopupUI: public QWidget, public Ui_wdgWheelPreferencesPopup { WheelPreferencesPopupUI() { setupUi(this); } }; ArtisticColorSelectorDock::ArtisticColorSelectorDock() : QDockWidget(i18n("Artistic Color Selector")) , m_canvas(nullptr) , m_resourceProvider(0) , m_selectedMask(nullptr) { setEnabled(false); m_hsxButtons = new QButtonGroup(); m_preferencesUI = new ARCSSettingsUI(); m_wheelPrefsUI = new WheelPreferencesPopupUI(); m_selectorUI = new ArtisticColorSelectorUI(); QPixmap hueStepsPixmap = KisIconUtils::loadIcon("wheel-sectors").pixmap(16,16); QPixmap saturationStepsPixmap = KisIconUtils::loadIcon("wheel-rings").pixmap(16,16); QPixmap valueScaleStepsPixmap = KisIconUtils::loadIcon("wheel-light").pixmap(16,16); QIcon infinityIcon = KisIconUtils::loadIcon("infinity"); m_infinityPixmap = infinityIcon.pixmap(16,16); m_selectorUI->colorSelector->loadSettings(); m_selectorUI->bnWheelPrefs->setIcon(KisIconUtils::loadIcon("wheel-sectors")); m_selectorUI->bnWheelPrefs->setPopupWidget(m_wheelPrefsUI); m_selectorUI->bnDockerPrefs->setPopupWidget(m_preferencesUI); m_selectorUI->bnDockerPrefs->setIcon(KisIconUtils::loadIcon("configure")); //preferences m_hsxButtons->addButton(m_preferencesUI->bnHsy, KisColor::HSY); m_hsxButtons->addButton(m_preferencesUI->bnHsi, KisColor::HSI); m_hsxButtons->addButton(m_preferencesUI->bnHsl, KisColor::HSL); m_hsxButtons->addButton(m_preferencesUI->bnHsv, KisColor::HSV); m_wheelPrefsUI->bnInverseSat->setChecked(m_selectorUI->colorSelector->isSaturationInverted()); m_wheelPrefsUI->labelHueSteps->setPixmap(hueStepsPixmap); m_wheelPrefsUI->labelSaturationSteps->setPixmap(saturationStepsPixmap); m_wheelPrefsUI->labelValueScaleSteps->setPixmap(valueScaleStepsPixmap); m_wheelPrefsUI->numHueSteps->setRange(MIN_NUM_UI_HUE_PIECES, MAX_NUM_HUE_PIECES); m_wheelPrefsUI->numSaturationSteps->setRange(MIN_NUM_SATURATION_RINGS, MAX_NUM_SATURATION_RINGS); m_wheelPrefsUI->numValueScaleSteps->setRange(MIN_NUM_UI_LIGHT_PIECES, MAX_NUM_LIGHT_PIECES); m_wheelPrefsUI->bnInfHueSteps->setIcon(infinityIcon); m_wheelPrefsUI->bnInfValueScaleSteps->setIcon(infinityIcon); m_wheelPrefsUI->bnInfHueSteps->setToolTip(i18n("Continuous Mode")); m_wheelPrefsUI->bnInfValueScaleSteps->setToolTip(i18n("Continuous Mode")); int selectorHueSteps = m_selectorUI->colorSelector->getNumPieces(); if (selectorHueSteps == 1) { m_wheelPrefsUI->bnInfHueSteps->setChecked(true); } else { m_wheelPrefsUI->bnInfHueSteps->setChecked(false); } m_wheelPrefsUI->numHueSteps->setValue(selectorHueSteps); m_wheelPrefsUI->numSaturationSteps->setValue(m_selectorUI->colorSelector->getNumRings()); int selectorValueScaleSteps = m_selectorUI->colorSelector->getNumLightPieces(); if (selectorValueScaleSteps == 1) { m_wheelPrefsUI->bnInfValueScaleSteps->setChecked(true); } else { m_wheelPrefsUI->bnInfValueScaleSteps->setChecked(false); } m_wheelPrefsUI->numValueScaleSteps->setValue(m_selectorUI->colorSelector->getNumLightPieces()); m_preferencesUI->bnDefInfHueSteps->setIcon(infinityIcon); m_preferencesUI->bnDefInfValueScaleSteps->setIcon(infinityIcon); m_preferencesUI->labelDefHueSteps->setPixmap(hueStepsPixmap); m_preferencesUI->labelDefSaturationSteps->setPixmap(saturationStepsPixmap); m_preferencesUI->labelDefValueScaleSteps->setPixmap(valueScaleStepsPixmap); m_preferencesUI->defaultHueSteps->setRange(MIN_NUM_HUE_PIECES, MAX_NUM_HUE_PIECES); m_preferencesUI->defaultSaturationSteps->setRange(MIN_NUM_SATURATION_RINGS, MAX_NUM_SATURATION_RINGS); m_preferencesUI->defaultValueScaleSteps->setRange(MIN_NUM_LIGHT_PIECES, MAX_NUM_LIGHT_PIECES); m_preferencesUI->defaultHueSteps->setValue(m_selectorUI->colorSelector->getDefaultHueSteps()); m_preferencesUI->defaultSaturationSteps->setValue(m_selectorUI->colorSelector->getDefaultSaturationSteps()); m_preferencesUI->defaultValueScaleSteps->setValue(m_selectorUI->colorSelector->getDefaultValueScaleSteps()); m_preferencesUI->showBgColor->setChecked(m_selectorUI->colorSelector->getShowBgColor()); m_preferencesUI->showValueScaleNumbers->setChecked(m_selectorUI->colorSelector->getShowValueScaleNumbers()); m_preferencesUI->enforceGamutMask->setChecked(m_selectorUI->colorSelector->enforceGamutMask()); m_preferencesUI->permissiveGamutMask->setChecked(!m_selectorUI->colorSelector->enforceGamutMask()); m_preferencesUI->spLumaR->setValue(m_selectorUI->colorSelector->lumaR()); m_preferencesUI->spLumaG->setValue(m_selectorUI->colorSelector->lumaG()); m_preferencesUI->spLumaB->setValue(m_selectorUI->colorSelector->lumaB()); m_preferencesUI->spLumaGamma->setValue(m_selectorUI->colorSelector->lumaGamma()); switch(m_selectorUI->colorSelector->getColorSpace()) { case KisColor::HSV: { m_preferencesUI->bnHsv->setChecked(true); } break; case KisColor::HSI: { m_preferencesUI->bnHsi->setChecked(true); } break; case KisColor::HSL: { m_preferencesUI->bnHsl->setChecked(true); } break; case KisColor::HSY: { m_preferencesUI->bnHsy->setChecked(true); } break; } if (m_selectorUI->colorSelector->getColorSpace() == KisColor::HSY) { m_preferencesUI->lumaCoefficientBox->show(); } else { m_preferencesUI->lumaCoefficientBox->hide(); } connect(m_wheelPrefsUI->numValueScaleSteps , SIGNAL(valueChanged(int)) , SLOT(slotPreferenceChanged())); connect(m_wheelPrefsUI->numHueSteps , SIGNAL(valueChanged(int)) , SLOT(slotPreferenceChanged())); connect(m_wheelPrefsUI->numSaturationSteps , SIGNAL(valueChanged(int)) , SLOT(slotPreferenceChanged())); connect(m_wheelPrefsUI->bnInverseSat , SIGNAL(clicked(bool)) , SLOT(slotPreferenceChanged())); connect(m_wheelPrefsUI->bnInfHueSteps , SIGNAL(clicked(bool)) , SLOT(slotPreferenceChanged())); connect(m_wheelPrefsUI->bnInfValueScaleSteps, SIGNAL(clicked(bool)) , SLOT(slotPreferenceChanged())); connect(m_wheelPrefsUI->bnDefault , SIGNAL(clicked(bool)) , SLOT(slotResetDefaultSettings())); connect(m_preferencesUI->defaultHueSteps , SIGNAL(valueChanged(int)) , SLOT(slotPreferenceChanged())); connect(m_preferencesUI->defaultSaturationSteps, SIGNAL(valueChanged(int)) , SLOT(slotPreferenceChanged())); connect(m_preferencesUI->defaultValueScaleSteps, SIGNAL(valueChanged(int)) , SLOT(slotPreferenceChanged())); connect(m_preferencesUI->bnDefInfHueSteps , SIGNAL(clicked(bool)) , SLOT(slotPreferenceChanged())); connect(m_preferencesUI->bnDefInfValueScaleSteps, SIGNAL(clicked(bool)) , SLOT(slotPreferenceChanged())); connect(m_preferencesUI->showBgColor , SIGNAL(toggled(bool)) , SLOT(slotPreferenceChanged())); connect(m_preferencesUI->showValueScaleNumbers, SIGNAL(toggled(bool)) , SLOT(slotPreferenceChanged())); connect(m_preferencesUI->enforceGamutMask , SIGNAL(toggled(bool)) , SLOT(slotPreferenceChanged())); connect(m_preferencesUI->spLumaR , SIGNAL(valueChanged(qreal)), SLOT(slotColorSpaceSelected())); connect(m_preferencesUI->spLumaG , SIGNAL(valueChanged(qreal)), SLOT(slotColorSpaceSelected())); connect(m_preferencesUI->spLumaB , SIGNAL(valueChanged(qreal)), SLOT(slotColorSpaceSelected())); connect(m_preferencesUI->spLumaGamma , SIGNAL(valueChanged(qreal)), SLOT(slotColorSpaceSelected())); connect(m_selectorUI->colorSelector , SIGNAL(sigFgColorChanged(KisColor)) , SLOT(slotFgColorChanged(KisColor))); connect(m_selectorUI->colorSelector , SIGNAL(sigBgColorChanged(KisColor)) , SLOT(slotBgColorChanged(KisColor))); // gamut mask connections connect(m_selectorUI->gamutMaskToolbar, SIGNAL(sigGamutMaskToggle(bool)), SLOT(slotGamutMaskToggle(bool))); connect(m_hsxButtons , SIGNAL(buttonClicked(int)) , SLOT(slotColorSpaceSelected())); setWidget(m_selectorUI); } ArtisticColorSelectorDock::~ArtisticColorSelectorDock() { m_selectorUI->colorSelector->saveSettings(); delete m_hsxButtons; } void ArtisticColorSelectorDock::setViewManager(KisViewManager* kisview) { m_resourceProvider = kisview->resourceProvider(); m_selectorUI->colorSelector->setFgColor(m_resourceProvider->resourceManager()->foregroundColor()); m_selectorUI->colorSelector->setBgColor(m_resourceProvider->resourceManager()->backgroundColor()); - connect(m_resourceProvider, SIGNAL(sigGamutMaskChanged(KoGamutMask*)), - this, SLOT(slotGamutMaskSet(KoGamutMask*))); + connect(m_resourceProvider, SIGNAL(sigGamutMaskChanged(KoGamutMaskSP)), + this, SLOT(slotGamutMaskSet(KoGamutMaskSP))); connect(m_resourceProvider, SIGNAL(sigGamutMaskUnset()), this, SLOT(slotGamutMaskUnset())); connect(m_resourceProvider, SIGNAL(sigGamutMaskPreviewUpdate()), this, SLOT(slotGamutMaskPreviewUpdate())); m_selectorUI->gamutMaskToolbar->connectMaskSignals(m_resourceProvider); } void ArtisticColorSelectorDock::slotCanvasResourceChanged(int key, const QVariant& value) { if(key == KoCanvasResourceProvider::ForegroundColor) m_selectorUI->colorSelector->setFgColor(value.value()); if(key == KoCanvasResourceProvider::BackgroundColor) m_selectorUI->colorSelector->setBgColor(value.value()); } void ArtisticColorSelectorDock::slotFgColorChanged(const KisColor& color) { m_resourceProvider->resourceManager()->setForegroundColor( KoColor(color.toKoColor(), m_resourceProvider->resourceManager()->foregroundColor().colorSpace()) ); } void ArtisticColorSelectorDock::slotBgColorChanged(const KisColor& color) { m_resourceProvider->resourceManager()->setBackgroundColor( KoColor(color.toKoColor(), m_resourceProvider->resourceManager()->backgroundColor().colorSpace()) ); } void ArtisticColorSelectorDock::slotColorSpaceSelected() { KisColor::Type type = static_cast( m_hsxButtons->id(m_hsxButtons->checkedButton())); m_selectorUI->colorSelector->setColorSpace(type); if (type == KisColor::HSY) { m_preferencesUI->lumaCoefficientBox->show(); } else { m_preferencesUI->lumaCoefficientBox->hide(); } m_selectorUI->colorSelector->setLumaCoefficients( m_preferencesUI->spLumaR->value(), m_preferencesUI->spLumaG->value(), m_preferencesUI->spLumaB->value(), m_preferencesUI->spLumaGamma->value() ); } void ArtisticColorSelectorDock::slotPreferenceChanged() { int hueSteps = DEFAULT_HUE_STEPS; if (m_wheelPrefsUI->bnInfHueSteps->isChecked()) { m_wheelPrefsUI->numHueSteps->setEnabled(false); hueSteps = 1; } else { m_wheelPrefsUI->numHueSteps->setEnabled(true); hueSteps = m_wheelPrefsUI->numHueSteps->value(); } m_selectorUI->colorSelector->setNumPieces(hueSteps); m_selectorUI->colorSelector->setNumRings(m_wheelPrefsUI->numSaturationSteps->value()); int valueScaleSteps; if (m_wheelPrefsUI->bnInfValueScaleSteps->isChecked()) { m_wheelPrefsUI->numValueScaleSteps->setEnabled(false); valueScaleSteps = 1; } else { valueScaleSteps = m_wheelPrefsUI->numValueScaleSteps->value(); m_wheelPrefsUI->numValueScaleSteps->setEnabled(true); } m_selectorUI->colorSelector->setNumLightPieces(valueScaleSteps); int defHueSteps; if (m_preferencesUI->bnDefInfHueSteps->isChecked()) { m_preferencesUI->defaultHueSteps->setEnabled(false); defHueSteps = 1; } else { m_preferencesUI->defaultHueSteps->setEnabled(true); defHueSteps = m_preferencesUI->defaultHueSteps->value(); } m_selectorUI->colorSelector->setDefaultHueSteps(defHueSteps); m_selectorUI->colorSelector->setDefaultSaturationSteps(m_preferencesUI->defaultSaturationSteps->value()); int defValueScaleSteps; if (m_preferencesUI->bnDefInfValueScaleSteps->isChecked()) { m_preferencesUI->defaultValueScaleSteps->setEnabled(false); defValueScaleSteps = 1; } else { m_preferencesUI->defaultValueScaleSteps->setEnabled(true); defValueScaleSteps = m_preferencesUI->defaultValueScaleSteps->value(); } m_selectorUI->colorSelector->setDefaultValueScaleSteps(defValueScaleSteps); m_selectorUI->colorSelector->setShowBgColor(m_preferencesUI->showBgColor->isChecked()); m_selectorUI->colorSelector->setShowValueScaleNumbers(m_preferencesUI->showValueScaleNumbers->isChecked()); m_selectorUI->colorSelector->setEnforceGamutMask(m_preferencesUI->enforceGamutMask->isChecked()); m_selectorUI->colorSelector->setInverseSaturation(m_wheelPrefsUI->bnInverseSat->isChecked()); } void ArtisticColorSelectorDock::slotResetDefaultSettings() { quint32 hueSteps = m_selectorUI->colorSelector->getDefaultHueSteps(); quint32 saturationSteps = m_selectorUI->colorSelector->getDefaultSaturationSteps(); quint32 valueScaleSteps = m_selectorUI->colorSelector->getDefaultValueScaleSteps(); m_selectorUI->colorSelector->setNumRings(saturationSteps); m_wheelPrefsUI->numSaturationSteps->blockSignals(true); m_wheelPrefsUI->numSaturationSteps->setValue(saturationSteps); m_wheelPrefsUI->numSaturationSteps->blockSignals(false); m_selectorUI->colorSelector->setNumPieces(hueSteps); m_wheelPrefsUI->numHueSteps->blockSignals(true); m_wheelPrefsUI->numHueSteps->setValue(hueSteps); m_wheelPrefsUI->numHueSteps->blockSignals(false); if (hueSteps == 1) { m_wheelPrefsUI->numHueSteps->setEnabled(false); m_wheelPrefsUI->bnInfHueSteps->setChecked(true); } else { m_wheelPrefsUI->numHueSteps->setEnabled(true); m_wheelPrefsUI->bnInfHueSteps->setChecked(false); } m_selectorUI->colorSelector->setNumLightPieces(valueScaleSteps); m_wheelPrefsUI->numValueScaleSteps->blockSignals(true); m_wheelPrefsUI->numValueScaleSteps->setValue(valueScaleSteps); m_wheelPrefsUI->numValueScaleSteps->blockSignals(false); if (valueScaleSteps == 1) { m_wheelPrefsUI->numValueScaleSteps->setEnabled(false); m_wheelPrefsUI->bnInfValueScaleSteps->setChecked(true); } else { m_wheelPrefsUI->numValueScaleSteps->setEnabled(true); m_wheelPrefsUI->bnInfValueScaleSteps->setChecked(false); } } void ArtisticColorSelectorDock::slotGamutMaskToggle(bool checked) { bool b = (!m_selectedMask) ? false : checked; if (b == true) { m_selectorUI->colorSelector->setGamutMask(m_selectedMask); } m_selectorUI->colorSelector->setGamutMaskOn(b); } void ArtisticColorSelectorDock::setCanvas(KoCanvasBase *canvas) { if (!canvas) { return; } m_canvas = dynamic_cast(canvas); if (m_canvas) { m_canvas->disconnectCanvasObserver(this); } if (m_canvas) { connect(m_canvas->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)), SLOT(slotCanvasResourceChanged(int,QVariant))); connect(m_canvas->displayColorConverter(), SIGNAL(displayConfigurationChanged()), SLOT(slotSelectorSettingsChanged())); m_selectorUI->colorSelector->setColorConverter(m_canvas->displayColorConverter()); setEnabled(true); } } void ArtisticColorSelectorDock::unsetCanvas() { setEnabled(false); m_canvas = nullptr; m_selectorUI->colorSelector->setColorConverter(KisDisplayColorConverter::dumbConverterInstance()); } -void ArtisticColorSelectorDock::slotGamutMaskSet(KoGamutMask *mask) +void ArtisticColorSelectorDock::slotGamutMaskSet(KoGamutMaskSP mask) { if (!mask) { return; } m_selectedMask = mask; if (m_selectedMask) { m_selectorUI->colorSelector->setGamutMask(m_selectedMask); slotGamutMaskToggle(true); } else { slotGamutMaskToggle(false); } } void ArtisticColorSelectorDock::slotGamutMaskUnset() { if (!m_selectedMask) { return; } m_selectedMask = nullptr; slotGamutMaskToggle(false); m_selectorUI->colorSelector->setGamutMask(m_selectedMask); } void ArtisticColorSelectorDock::slotGamutMaskPreviewUpdate() { m_selectorUI->colorSelector->update(); } void ArtisticColorSelectorDock::slotSelectorSettingsChanged() { m_selectorUI->colorSelector->setDirty(); } diff --git a/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.h b/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.h index 23112382c8..cf0f6c5023 100644 --- a/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.h +++ b/plugins/dockers/artisticcolorselector/artisticcolorselector_dock.h @@ -1,86 +1,86 @@ /* * Copyright (c) 2009 Cyrille Berger * * 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; version 2.1 of the License. * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef H_ARTISTIC_COLOR_SELECTOR_DOCK_H #define H_ARTISTIC_COLOR_SELECTOR_DOCK_H #include #include #include #include #include #include #include #include #include #include #include #include class KisCanvasResourceProvider; class KisColor; class QButtonGroup; class QMenu; struct ArtisticColorSelectorUI; struct ARCSSettingsUI; struct WheelPreferencesPopupUI; class ArtisticColorSelectorDock: public QDockWidget, public KisMainwindowObserver { Q_OBJECT public: ArtisticColorSelectorDock(); ~ArtisticColorSelectorDock() override; QString observerName() override { return "ArtisticColorSelectorDock"; } void setViewManager(KisViewManager* kisview) override; void setCanvas(KoCanvasBase* canvas) override; void unsetCanvas() override; private Q_SLOTS: void slotCanvasResourceChanged(int key, const QVariant& value); void slotFgColorChanged(const KisColor& color); void slotBgColorChanged(const KisColor& color); void slotColorSpaceSelected(); void slotPreferenceChanged(); void slotResetDefaultSettings(); void slotGamutMaskToggle(bool value); - void slotGamutMaskSet(KoGamutMask* mask); + void slotGamutMaskSet(KoGamutMaskSP mask); void slotGamutMaskUnset(); void slotGamutMaskPreviewUpdate(); void slotSelectorSettingsChanged(); private: KisCanvas2* m_canvas; KisCanvasResourceProvider* m_resourceProvider; QButtonGroup* m_hsxButtons; ArtisticColorSelectorUI* m_selectorUI; ARCSSettingsUI* m_preferencesUI; WheelPreferencesPopupUI* m_wheelPrefsUI; - KoGamutMask* m_selectedMask; + KoGamutMaskSP m_selectedMask; QIcon m_iconMaskOff; QIcon m_iconMaskOn; QPixmap m_infinityPixmap; }; #endif // H_ARTISTIC_COLOR_SELECTOR_DOCK_H diff --git a/plugins/dockers/artisticcolorselector/kis_color_selector.cpp b/plugins/dockers/artisticcolorselector/kis_color_selector.cpp index 5427d80fc5..f4d1ac8f7d 100644 --- a/plugins/dockers/artisticcolorselector/kis_color_selector.cpp +++ b/plugins/dockers/artisticcolorselector/kis_color_selector.cpp @@ -1,1185 +1,1185 @@ /* Copyright (C) 2011 Silvio Heinrich 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_color_selector.h" //#define DEBUG_ARC_SELECTOR KisColorSelector::KisColorSelector(QWidget* parent, KisColor::Type type) : QWidget(parent) , m_colorConverter(KisDisplayColorConverter::dumbConverterInstance()) , m_colorSpace(type) , m_inverseSaturation(false) , m_selectedColor(m_colorConverter) , m_fgColor(m_colorConverter) , m_bgColor(m_colorConverter) , m_clickedRing(-1) , m_gamutMaskOn(false) , m_currentGamutMask(nullptr) , m_maskPreviewActive(true) , m_widgetUpdatesSelf(false) , m_isDirtyWheel(false) , m_isDirtyLightStrip(false) , m_isDirtyGamutMask(false) , m_isDirtyColorPreview(false) { m_viewConverter = new KisGamutMaskViewConverter(); setLumaCoefficients(DEFAULT_LUMA_R, DEFAULT_LUMA_G, DEFAULT_LUMA_B,DEFAULT_LUMA_GAMMA); recalculateRings(DEFAULT_SATURATION_STEPS, DEFAULT_HUE_STEPS); recalculateAreas(DEFAULT_VALUE_SCALE_STEPS); selectColor(KisColor(Qt::red, m_colorConverter, KisColor::HSY, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma)); using namespace std::placeholders; // For _1 placeholder auto function = std::bind(&KisColorSelector::slotUpdateColorAndPreview, this, _1); m_updateColorCompressor.reset(new ColorCompressorType(20 /* ms */, function)); } void KisColorSelector::setColorSpace(KisColor::Type type) { m_colorSpace = type; m_selectedColor = KisColor(m_selectedColor, m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma); m_isDirtyLightStrip = true; m_isDirtyWheel = true; #ifdef DEBUG_ARC_SELECTOR dbgPlugins << "KisColorSelector::setColorSpace: set to:" << m_colorSpace; #endif update(); } void KisColorSelector::setColorConverter(KisDisplayColorConverter *colorConverter) { m_colorConverter = colorConverter; m_selectedColor = KisColor(m_selectedColor, m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma); m_fgColor = KisColor(m_fgColor, m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma); m_bgColor = KisColor(m_bgColor, m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma); update(); } void KisColorSelector::setNumLightPieces(int num) { num = qBound(MIN_NUM_LIGHT_PIECES, num, MAX_NUM_LIGHT_PIECES); recalculateAreas(quint8(num)); if (m_selectedLightPiece >= 0) m_selectedLightPiece = getLightIndex(m_selectedColor.getX()); update(); } void KisColorSelector::setNumPieces(int num) { num = qBound(MIN_NUM_HUE_PIECES, num, MAX_NUM_HUE_PIECES); recalculateRings(quint8(getNumRings()), quint8(num)); if (m_selectedPiece >= 0) m_selectedPiece = getHueIndex(m_selectedColor.getH() * PI2); update(); } void KisColorSelector::setNumRings(int num) { num = qBound(MIN_NUM_SATURATION_RINGS, num, MAX_NUM_SATURATION_RINGS); recalculateRings(quint8(num), quint8(getNumPieces())); if (m_selectedRing >= 0) m_selectedRing = getSaturationIndex(m_selectedColor.getS()); update(); } void KisColorSelector::selectColor(const KisColor& color) { m_selectedColor = KisColor(color, m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma); m_selectedPiece = getHueIndex(m_selectedColor.getH() * PI2); m_selectedRing = getSaturationIndex(m_selectedColor.getS()); m_selectedLightPiece = getLightIndex(m_selectedColor.getX()); update(); } void KisColorSelector::setFgColor(const KoColor& fgColor) { if (!m_widgetUpdatesSelf) { m_fgColor = KisColor(fgColor, m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma); m_selectedColor = KisColor(fgColor, m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma); m_isDirtyWheel = true; m_isDirtyLightStrip = true; m_isDirtyColorPreview = true; #ifdef DEBUG_ARC_SELECTOR dbgPlugins << "KisColorSelector::setFgColor: m_fgColor set to:" << "H:" << m_fgColor.getH() << "S:" << m_fgColor.getS() << "X:" << m_fgColor.getX(); dbgPlugins << "KisColorSelector::setFgColor: m_selectedColor set to:" << "H:" << m_selectedColor.getH() << "S:" << m_selectedColor.getS() << "X:" << m_selectedColor.getX(); #endif update(); } } void KisColorSelector::setBgColor(const KoColor& bgColor) { if (!m_widgetUpdatesSelf) { m_bgColor = KisColor(bgColor, m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma); m_isDirtyColorPreview = true; #ifdef DEBUG_ARC_SELECTOR dbgPlugins << "KisColorSelector::setBgColor: m_bgColor set to:" << "H:" << m_bgColor.getH() << "S:" << m_bgColor.getS() << "X:" << m_bgColor.getX(); #endif update(); } } void KisColorSelector::setLight(qreal light) { m_selectedColor.setX(qBound(0.0, light, 1.0)); m_selectedLightPiece = getLightIndex(m_selectedColor.getX()); m_isDirtyLightStrip = true; update(); } void KisColorSelector::setLumaCoefficients(qreal lR, qreal lG, qreal lB, qreal lGamma) { m_lumaR = lR; m_lumaG = lG; m_lumaB = lB; m_lumaGamma = lGamma; m_selectedColor = KisColor(m_selectedColor, m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma); m_isDirtyLightStrip = true; m_isDirtyWheel = true; #ifdef DEBUG_ARC_SELECTOR dbgPlugins << "KisColorSelector::setLumaCoefficients: " << m_lumaR << " " << m_lumaG << " " << m_lumaB << " " << m_lumaGamma; #endif update(); } void KisColorSelector::setInverseSaturation(bool inverse) { if (m_inverseSaturation != inverse) { m_selectedRing = (getNumRings()-1) - m_selectedRing; m_inverseSaturation = inverse; recalculateRings(quint8(getNumRings()), quint8(getNumPieces())); update(); } } -void KisColorSelector::setGamutMask(KoGamutMask* gamutMask) +void KisColorSelector::setGamutMask(KoGamutMaskSP gamutMask) { if (!gamutMask) { return; } m_currentGamutMask = gamutMask; m_viewConverter->setViewSize(m_renderAreaSize); m_viewConverter->setMaskSize(m_currentGamutMask->maskSize()); if (m_enforceGamutMask) { m_isDirtyWheel = true; } else { m_isDirtyGamutMask = true; } update(); } void KisColorSelector::setDirty() { m_isDirtyWheel = true; m_isDirtyLightStrip = true; m_isDirtyGamutMask = true; m_isDirtyColorPreview = true; update(); } -KoGamutMask* KisColorSelector::gamutMask() +KoGamutMaskSP KisColorSelector::gamutMask() { return m_currentGamutMask; } bool KisColorSelector::gamutMaskOn() { return m_gamutMaskOn; } void KisColorSelector::setGamutMaskOn(bool gamutMaskOn) { if (m_currentGamutMask) { m_gamutMaskOn = gamutMaskOn; if (m_enforceGamutMask) { m_isDirtyWheel = true; } else { m_isDirtyGamutMask = true; } update(); } } void KisColorSelector::setEnforceGamutMask(bool enforce) { m_enforceGamutMask = enforce; m_isDirtyGamutMask = true; m_isDirtyWheel = true; update(); } QPointF KisColorSelector::mapCoordToView(const QPointF& pt, const QRectF& viewRect) const { qreal w = viewRect.width() / 2.0; qreal h = viewRect.height() / 2.0; qreal x = pt.x() + 1.0; qreal y = (pt.y()) + 1.0; return QPointF(x*w, y*h); } QPointF KisColorSelector::mapCoordToUnit(const QPointF& pt, const QRectF& viewRect) const { qreal w = viewRect.width() / 2.0; qreal h = viewRect.height() / 2.0; qreal x = pt.x() - (viewRect.x() + w); qreal y = pt.y() - (viewRect.y() + h); return QPointF(x/w, y/h); } QPointF KisColorSelector::mapColorToUnit(const KisColor& color, bool invertSaturation) const { qreal radius; if (invertSaturation && m_inverseSaturation) { radius = 1.0 - color.getS(); } else { radius = color.getS(); } QPointF hueCoord = mapHueToAngle(color.getH()); qreal x = hueCoord.x()*radius; qreal y = hueCoord.y()*radius; return QPointF(x,y); } KisColorSelector::Radian KisColorSelector::mapCoordToAngle(qreal x, qreal y) const { qreal angle = std::atan2(-y, -x); #ifdef DEBUG_ARC_SELECTOR dbgPlugins << "KisColorSelector::mapCoordToAngle: " << "X:" << x << "Y:" << y << "angle:" << angle; #endif return angle; } QPointF KisColorSelector::mapHueToAngle(qreal hue) const { qreal angle = hue * 2.0 * M_PI - M_PI; qreal x = std::cos(angle); qreal y = std::sin(angle); return QPointF(x,y); } qint8 KisColorSelector::getLightIndex(const QPointF& pt) const { if (m_lightStripArea.contains(pt.toPoint(), true)) { qreal t = (pt.x() - m_lightStripArea.x()) / qreal(m_lightStripArea.width()); t = (pt.y() - m_lightStripArea.y()) / qreal(m_lightStripArea.height()); return qint8(t * getNumLightPieces()); } return -1; } qint8 KisColorSelector::getLightIndex(qreal light) const { light = qreal(1) - qBound(qreal(0), light, qreal(1)); return qint8(qRound(light * (getNumLightPieces()-1))); } qreal KisColorSelector::getLight(const QPointF& pt) const { qint8 clickedLightPiece = getLightIndex(pt); if (clickedLightPiece >= 0) { if (getNumLightPieces() > 1) { return 1.0 - (qreal(clickedLightPiece) / qreal(getNumLightPieces()-1)); } return 1.0 - (qreal(pt.y()) / qreal(m_lightStripArea.height())); } return qreal(0); } qint8 KisColorSelector::getHueIndex(Radian hue) const { qreal partSize = 1.0 / qreal(getNumPieces()); return qint8(qRound(hue.scaled(0.0, 1.0) / partSize) % getNumPieces()); } qreal KisColorSelector::getHue(int hueIdx, Radian shift) const { Radian hue = (qreal(hueIdx) / qreal(getNumPieces())) * PI2; hue += shift; return hue.scaled(0.0, 1.0); } qint8 KisColorSelector::getSaturationIndex(qreal saturation) const { saturation = qBound(qreal(0), saturation, qreal(1)); saturation = m_inverseSaturation ? (qreal(1) - saturation) : saturation; return qint8(saturation * qreal(getNumRings() - 1)); } qint8 KisColorSelector::getSaturationIndex(const QPointF& pt) const { qreal length = std::sqrt(pt.x()*pt.x() + pt.y()*pt.y()); for(int i=0; i= m_colorRings[i].innerRadius && length < m_colorRings[i].outerRadius) return qint8(i); } return -1; } qreal KisColorSelector::getSaturation(int saturationIdx) const { qreal sat = qreal(saturationIdx) / qreal(getNumRings()-1); return m_inverseSaturation ? (1.0 - sat) : sat; } void KisColorSelector::recalculateAreas(quint8 numLightPieces) { qreal LIGHT_STRIP_RATIO = 0.075; if (m_showValueScaleNumbers) { LIGHT_STRIP_RATIO = 0.25; } int width = QWidget::width(); int height = QWidget::height(); int size = qMin(width, height); int stripThick = int(size * LIGHT_STRIP_RATIO); width -= stripThick; size = qMin(width, height); int x = (width - size) / 2; int y = (height - size) / 2; m_renderAreaSize = QSize(size,size); m_viewConverter->setViewSize(m_renderAreaSize); m_widgetArea = QRect(0, 0, QWidget::width(), QWidget::height()); m_renderArea = QRect(x+stripThick, y, size, size); m_lightStripArea = QRect(0, 0, stripThick, QWidget::height()); m_renderBuffer = QImage(size, size, QImage::Format_ARGB32_Premultiplied); m_colorPreviewBuffer = QImage(QWidget::width(), QWidget::height(), QImage::Format_ARGB32_Premultiplied); m_maskBuffer = QImage(size, size, QImage::Format_ARGB32_Premultiplied); m_lightStripBuffer = QImage(stripThick, QWidget::height(), QImage::Format_ARGB32_Premultiplied); m_numLightPieces = numLightPieces; m_isDirtyGamutMask = true; m_isDirtyLightStrip = true; m_isDirtyWheel = true; m_isDirtyColorPreview = true; } void KisColorSelector::recalculateRings(quint8 numRings, quint8 numPieces) { m_colorRings.resize(numRings); m_numPieces = numPieces; for(int i=0; i(numPieces, 1); ring.innerRadius = innerRadius; ring.outerRadius = outerRadius; ring.pieced.resize(numParts); qreal partSize = 360.0 / qreal(numParts); QRectF outerRect(-outerRadius, -outerRadius, outerRadius*2.0, outerRadius*2.0); QRectF innerRect(-innerRadius, -innerRadius, innerRadius*2.0, innerRadius*2.0); for(int i=0; icoordIsClear(colorCoord, *m_viewConverter, m_maskPreviewActive); if (isClear) { return true; } else { return false; } } else { return true; } return false; } void KisColorSelector::requestUpdateColorAndPreview(const KisColor &color, Acs::ColorRole role) { #ifdef DEBUG_ARC_SELECTOR dbgPlugins << "KisColorSelector::requestUpdateColorAndPreview: requesting update to: " << "H:" << color.getH() << "S:" << color.getS() << "X:" << color.getX(); #endif m_updateColorCompressor->start(qMakePair(color, role)); } void KisColorSelector::slotUpdateColorAndPreview(QPair color) { const bool selectAsFgColor = color.second == Acs::Foreground; if (selectAsFgColor) { m_fgColor = KisColor(color.first, m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma); } else { m_bgColor = KisColor(color.first, m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma); } m_selectedColor = KisColor(color.first, m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma); m_isDirtyLightStrip = true; m_isDirtyColorPreview = true; m_isDirtyWheel = true; #ifdef DEBUG_ARC_SELECTOR dbgPlugins << "KisColorSelector::slotUpdateColorAndPreview: m_selectedColor set to:" << "H:" << m_selectedColor.getH() << "S:" << m_selectedColor.getS() << "X:" << m_selectedColor.getX(); #endif if (selectAsFgColor) { emit sigFgColorChanged(m_selectedColor); } else { emit sigBgColorChanged(m_selectedColor); } } void KisColorSelector::drawRing(QPainter& painter, KisColorSelector::ColorRing& ring, const QRect& rect) { painter.save(); painter.setRenderHint(QPainter::Antialiasing, true); painter.resetTransform(); painter.translate(rect.width()/2, rect.height()/2); if (ring.pieced.size() > 1) { QTransform mirror; mirror.rotate(180, Qt::YAxis); painter.setTransform(mirror, true); painter.scale(rect.width()/2, rect.height()/2); QPen normalPen = QPen(QBrush(COLOR_NORMAL_OUTLINE), 0.005); QPen clearMaskPen = QPen(QBrush(COLOR_MASK_CLEAR), 0.005); QBrush brush(Qt::SolidPattern); for(int i=0; i= 1.0) ? (hue - 1.0) : hue; hue = (hue < 0.0) ? (hue + 1.0) : hue; KisColor color(hue, m_colorConverter, m_colorSpace); color.setS(ring.saturation); color.setX(m_selectedColor.getX()); if(m_gamutMaskOn && m_enforceGamutMask && colorIsClear(color)) { painter.setPen(clearMaskPen); } else { painter.setPen(normalPen); } if ((m_enforceGamutMask) && (!colorIsClear(color))) { brush.setColor(COLOR_MASK_FILL); } else { brush.setColor(color.toQColor()); } painter.setBrush(brush); painter.drawPath(ring.pieced[i]); } } else { KisColor colors[7] = { KisColor(Qt::cyan , m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma), KisColor(Qt::green , m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma), KisColor(Qt::yellow , m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma), KisColor(Qt::red , m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma), KisColor(Qt::magenta, m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma), KisColor(Qt::blue , m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma), KisColor(Qt::cyan , m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma) }; QConicalGradient gradient(0, 0, 0); for(int i=0; i<=6; ++i) { qreal hue = qreal(i) / 6.0; colors[i].setS(ring.saturation); colors[i].setX(m_selectedColor.getX()); gradient.setColorAt(hue, colors[i].toQColor()); } painter.scale(rect.width()/2, rect.height()/2); painter.fillPath(ring.pieced[0], QBrush(gradient)); } painter.restore(); } void KisColorSelector::drawOutline(QPainter& painter, const QRect& rect) { painter.save(); painter.setRenderHint(QPainter::Antialiasing, true); painter.resetTransform(); painter.translate(rect.x() + rect.width()/2, rect.y() + rect.height()/2); painter.scale(rect.width()/2, rect.height()/2); QPen normalPen = QPen(QBrush(COLOR_NORMAL_OUTLINE), 0.005); QPen selectedPen; painter.setPen(normalPen); if (getNumPieces() > 1) { if (m_selectedRing >= 0 && m_selectedPiece >= 0) { painter.resetTransform(); painter.translate(rect.x() + rect.width()/2, rect.y() + rect.height()/2); QTransform mirror; mirror.rotate(180, Qt::YAxis); painter.setTransform(mirror, true); painter.scale(rect.width()/2, rect.height()/2); if (m_selectedColor.getX() < 0.55) { selectedPen = QPen(QBrush(COLOR_SELECTED_LIGHT), 0.007); } else { selectedPen = QPen(QBrush(COLOR_SELECTED_DARK), 0.007); } painter.setPen(selectedPen); painter.drawPath(m_colorRings[m_selectedRing].pieced[m_selectedPiece]); } } else { for(int i=0; i= 0) { qreal iRad = m_colorRings[m_selectedRing].innerRadius; qreal oRad = m_colorRings[m_selectedRing].outerRadius; if (m_selectedColor.getX() < 0.55) { selectedPen = QPen(QBrush(COLOR_SELECTED_LIGHT), 0.005); } else { selectedPen = QPen(QBrush(COLOR_SELECTED_DARK), 0.005); } painter.setPen(selectedPen); painter.drawEllipse(QRectF(-iRad, -iRad, iRad*2.0, iRad*2.0)); painter.drawEllipse(QRectF(-oRad, -oRad, oRad*2.0, oRad*2.0)); QPointF lineCoords = mapHueToAngle(m_selectedColor.getH()); painter.drawLine(QPointF(lineCoords.x()*iRad, lineCoords.y()*iRad), QPointF(lineCoords.x()*oRad, lineCoords.y()*oRad)); } } painter.restore(); } void KisColorSelector::drawLightStrip(QPainter& painter, const QRect& rect) { qreal penSize = qreal(qMin(QWidget::width(), QWidget::height())) / 200.0; qreal penSizeSmall = penSize / 1.2; QPen selectedPen; KisColor valueScaleColor(m_selectedColor, m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma); KisColor grayScaleColor(Qt::gray, m_colorConverter, m_colorSpace, m_lumaR, m_lumaG, m_lumaB, m_lumaGamma); int rectSize = rect.height(); painter.save(); painter.resetTransform(); painter.setRenderHint(QPainter::Antialiasing, true); QTransform matrix; matrix.translate(rect.x(), rect.y()); matrix.scale(rect.width(), rect.height()); qreal rectColorLeftX; qreal rectColorWidth; if (m_showValueScaleNumbers) { rectColorLeftX = 0.6; rectColorWidth = 0.4; } else { rectColorLeftX = 0.0; rectColorWidth = 1.0; } if (getNumLightPieces() > 1) { for(int i=0; i 0) && (fm.boundingRect("100%").width() > rect.width()*rectColorLeftX)) { font.setPointSize(font.pointSize() - 1); painter.setFont(font); fm = painter.fontMetrics(); retries--; } for(int i=0; i 0) { int valueNumber = 0; if (m_colorSpace == KisColor::HSY) { valueNumber = 100 - round(pow(pow(grayScaleColor.getX(), m_lumaGamma), 1.0/2.2)*100); } else { valueNumber = 100 - grayScaleColor.getX()*100; } if (valueNumber < 55) { painter.setPen(QPen(QBrush(COLOR_DARK), penSize)); } else { painter.setPen(QPen(QBrush(COLOR_LIGHT), penSize)); } painter.drawText(rectValue, Qt::AlignRight|Qt::AlignBottom, QString("%1%").arg(QString::number(valueNumber))); } } } painter.restore(); } void KisColorSelector::drawBlip(QPainter& painter, const QRect& rect) { painter.save(); painter.setRenderHint(QPainter::Antialiasing, true); painter.resetTransform(); painter.translate(rect.x() + rect.width()/2, rect.y() + rect.height()/2); painter.scale(rect.width()/2, rect.height()/2); QPointF fgColorPos = mapColorToUnit(m_fgColor); #ifdef DEBUG_ARC_SELECTOR dbgPlugins << "KisColorSelector::drawBlip: " << "colorPoint H:" << m_fgColor.getH() << " S:" << m_fgColor.getS() << "-> coord X:" << fgColorPos.x() << " Y:" << fgColorPos.y(); #endif painter.setPen(QPen(QBrush(COLOR_SELECTED_DARK), 0.01)); painter.drawEllipse(fgColorPos, 0.05, 0.05); painter.setPen(QPen(QBrush(COLOR_SELECTED_LIGHT), 0.01)); painter.drawEllipse(fgColorPos, 0.04, 0.04); painter.restore(); } void KisColorSelector::drawGamutMaskShape(QPainter &painter, const QRect &rect) { painter.save(); painter.setRenderHint(QPainter::Antialiasing, true); painter.resetTransform(); painter.translate(rect.width()/2, rect.height()/2); painter.scale(rect.width()/2, rect.height()/2); painter.setPen(Qt::NoPen); painter.setBrush(COLOR_MASK_FILL); painter.drawEllipse(QPointF(0,0), 1.0, 1.0); painter.resetTransform(); painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); m_currentGamutMask->paint(painter, *m_viewConverter, m_maskPreviewActive); painter.setCompositionMode(QPainter::CompositionMode_SourceOver); m_currentGamutMask->paintStroke(painter, *m_viewConverter, m_maskPreviewActive); painter.restore(); } void KisColorSelector::drawColorPreview(QPainter &painter, const QRect &rect) { painter.save(); painter.setRenderHint(QPainter::Antialiasing, true); painter.fillRect(rect, m_fgColor.toQColor()); int bgSide = qMin(rect.width()*0.15,rect.height()*0.15); if (m_showBgColor) { QPointF bgPolyPoints[3] = { QPointF(rect.width(), rect.height()), QPointF(rect.width()-bgSide, rect.height()), QPointF(rect.width(), rect.height()-bgSide) }; painter.setBrush(m_bgColor.toQColor()); painter.setPen(m_bgColor.toQColor()); painter.drawPolygon(bgPolyPoints, 3); } painter.restore(); } void KisColorSelector::paintEvent(QPaintEvent* /*event*/) { QPainter wdgPainter(this); // draw the fg and bg color previews if (m_isDirtyColorPreview) { m_colorPreviewBuffer.fill(Qt::transparent); QPainter colorPreviewPainter(&m_colorPreviewBuffer); drawColorPreview(colorPreviewPainter, m_widgetArea); m_isDirtyColorPreview = false; } wdgPainter.drawImage(m_widgetArea, m_colorPreviewBuffer); // draw the fg and bg color previews // draw the wheel if (m_isDirtyWheel) { m_renderBuffer.fill(Qt::transparent); QPainter wheelPainter(&m_renderBuffer); for(int i=0; ilocalPos(), m_renderArea); m_mouseMoved = false; m_pressedButtons = event->buttons(); m_clickedRing = getSaturationIndex(m_clickPos); Acs::ColorRole colorRole = Acs::buttonsToRole(Qt::NoButton, m_pressedButtons); qint8 clickedLightPiece = getLightIndex(event->localPos()); if (clickedLightPiece >= 0) { setLight(getLight(event->localPos())); m_selectedLightPiece = clickedLightPiece; requestUpdateColorAndPreview(m_selectedColor, colorRole); m_mouseMoved = true; } else if (m_clickedRing >= 0) { if (getNumPieces() == 1) { Radian angle = mapCoordToAngle(m_clickPos.x(), m_clickPos.y()); KisColor color(m_colorConverter, m_colorSpace); color.setHSX(angle.scaled(0.0, 1.0) , getSaturation(m_clickedRing) , m_selectedColor.getX() ); #ifdef DEBUG_ARC_SELECTOR dbgPlugins << "KisColorSelector::mousePressEvent: picked color: " << "H:" << color.getH() << "S:" << color.getS() << "X:" << color.getX(); #endif if ((!m_enforceGamutMask) || colorIsClear(color)) { m_selectedColor.setHSX(color.getH(), color.getS(), color.getX()); requestUpdateColorAndPreview(m_selectedColor, colorRole); m_selectedRing = m_clickedRing; m_mouseMoved = true; update(); } } } } void KisColorSelector::mouseMoveEvent(QMouseEvent* event) { QPointF dragPos = mapCoordToUnit(event->localPos(), m_renderArea); qint8 clickedLightPiece = getLightIndex(event->localPos()); Acs::ColorRole colorRole = Acs::buttonsToRole(Qt::NoButton, m_pressedButtons); if (clickedLightPiece >= 0) { setLight(getLight(event->localPos())); m_selectedLightPiece = clickedLightPiece; requestUpdateColorAndPreview(m_selectedColor, colorRole); } if (m_clickedRing < 0) return; if (getNumPieces() == 1) { Radian angle = mapCoordToAngle(dragPos.x(), dragPos.y()); KisColor color(m_colorConverter, m_colorSpace); color.setHSX(angle.scaled(0.0, 1.0) , getSaturation(m_clickedRing) , m_selectedColor.getX() ); if ((!m_enforceGamutMask) || colorIsClear(color)) { m_selectedColor.setHSX(color.getH(), color.getS(), color.getX()); requestUpdateColorAndPreview(m_selectedColor, colorRole); } } update(); } void KisColorSelector::mouseReleaseEvent(QMouseEvent* /*event*/) { Acs::ColorRole colorRole = Acs::buttonsToRole(Qt::NoButton, m_pressedButtons); if (!m_mouseMoved && m_clickedRing >= 0) { Radian angle = mapCoordToAngle(m_clickPos.x(), m_clickPos.y()); KisColor color(m_colorConverter, m_colorSpace); qint8 hueIndex = getHueIndex(angle); if (getNumPieces() > 1) { color.setH(getHue(hueIndex)); } else { color.setH(angle.scaled(0.0, 1.0)); } color.setS(getSaturation(m_clickedRing)); color.setX(m_selectedColor.getX()); if ((!m_enforceGamutMask) || colorIsClear(color)) { m_selectedColor.setHSX(color.getH(), color.getS(), color.getX()); m_selectedPiece = hueIndex; m_selectedRing = m_clickedRing; requestUpdateColorAndPreview(m_selectedColor, colorRole); } } else if (m_mouseMoved) requestUpdateColorAndPreview(m_selectedColor, colorRole); m_clickedRing = -1; m_widgetUpdatesSelf = false; #ifdef DEBUG_ARC_SELECTOR dbgPlugins << "KisColorSelector::ReleasePressEvent: m_widgetUpdatesSelf = false"; #endif update(); } void KisColorSelector::resizeEvent(QResizeEvent* /*event*/) { recalculateAreas(quint8(getNumLightPieces())); } void KisColorSelector::leaveEvent(QEvent* /*e*/) { m_widgetUpdatesSelf = false; #ifdef DEBUG_ARC_SELECTOR dbgPlugins << "KisColorSelector::leaveEvent: m_widgetUpdatesSelf = false"; #endif } void KisColorSelector::saveSettings() { KisConfig cfg(false); cfg.writeEntry("ArtColorSel.ColorSpace" , qint32(m_colorSpace)); cfg.writeEntry("ArtColorSel.lumaR", qreal(m_lumaR)); cfg.writeEntry("ArtColorSel.lumaG", qreal(m_lumaG)); cfg.writeEntry("ArtColorSel.lumaB", qreal(m_lumaB)); cfg.writeEntry("ArtColorSel.lumaGamma", qreal(m_lumaGamma)); cfg.writeEntry("ArtColorSel.NumRings" , m_colorRings.size()); cfg.writeEntry("ArtColorSel.RingPieces" , qint32(m_numPieces)); cfg.writeEntry("ArtColorSel.LightPieces", qint32(m_numLightPieces)); cfg.writeEntry("ArtColorSel.InversedSaturation", m_inverseSaturation); cfg.writeEntry("ArtColorSel.Light" , m_selectedColor.getX()); cfg.writeEntry("ArtColorSel.SelColorH", m_selectedColor.getH()); cfg.writeEntry("ArtColorSel.SelColorS", m_selectedColor.getS()); cfg.writeEntry("ArtColorSel.SelColorX", m_selectedColor.getX()); cfg.writeEntry("ArtColorSel.defaultHueSteps", quint32(m_defaultHueSteps)); cfg.writeEntry("ArtColorSel.defaultSaturationSteps", quint32(m_defaultSaturationSteps)); cfg.writeEntry("ArtColorSel.defaultValueScaleSteps", quint32(m_defaultValueScaleSteps)); cfg.writeEntry("ArtColorSel.showBgColor", m_showBgColor); cfg.writeEntry("ArtColorSel.showValueScale", m_showValueScaleNumbers); cfg.writeEntry("ArtColorSel.enforceGamutMask", m_enforceGamutMask); } void KisColorSelector::loadSettings() { KisConfig cfg(true); m_defaultHueSteps = cfg.readEntry("ArtColorSel.defaultHueSteps", DEFAULT_HUE_STEPS); m_defaultSaturationSteps = cfg.readEntry("ArtColorSel.defaultSaturationSteps", DEFAULT_SATURATION_STEPS); m_defaultValueScaleSteps = cfg.readEntry("ArtColorSel.defaultValueScaleSteps", DEFAULT_VALUE_SCALE_STEPS); setNumLightPieces(cfg.readEntry("ArtColorSel.LightPieces", DEFAULT_VALUE_SCALE_STEPS)); KisColor::Type colorSpace = KisColor::Type(cfg.readEntry("ArtColorSel.ColorSpace" , KisColor::HSY)); setColorSpace(colorSpace); setLumaCoefficients(cfg.readEntry("ArtColorSel.lumaR", DEFAULT_LUMA_R), cfg.readEntry("ArtColorSel.lumaG", DEFAULT_LUMA_G), cfg.readEntry("ArtColorSel.lumaB", DEFAULT_LUMA_B), cfg.readEntry("ArtColorSel.lumaGamma", DEFAULT_LUMA_GAMMA)); m_selectedColor.setH(cfg.readEntry("ArtColorSel.SelColorH", 0.0)); m_selectedColor.setS(cfg.readEntry("ArtColorSel.SelColorS", 0.0)); m_selectedColor.setX(cfg.readEntry("ArtColorSel.SelColorX", 0.0)); setInverseSaturation(cfg.readEntry("ArtColorSel.InversedSaturation", false)); setLight(cfg.readEntry("ArtColorSel.Light", 0.5f)); setNumRings(cfg.readEntry("ArtColorSel.NumRings", DEFAULT_SATURATION_STEPS)); setNumPieces(cfg.readEntry("ArtColorSel.RingPieces", DEFAULT_HUE_STEPS)); m_showBgColor = cfg.readEntry("ArtColorSel.showBgColor", true); m_showValueScaleNumbers = cfg.readEntry("ArtColorSel.showValueScale", false); m_enforceGamutMask = cfg.readEntry("ArtColorSel.enforceGamutMask", false); selectColor(m_selectedColor); update(); } void KisColorSelector::setDefaultHueSteps(int num) { num = qBound(MIN_NUM_HUE_PIECES, num, MAX_NUM_HUE_PIECES); m_defaultHueSteps = num; } void KisColorSelector::setDefaultSaturationSteps(int num) { num = qBound(MIN_NUM_SATURATION_RINGS, num, MAX_NUM_SATURATION_RINGS); m_defaultSaturationSteps = num; } void KisColorSelector::setDefaultValueScaleSteps(int num) { num = qBound(MIN_NUM_LIGHT_PIECES, num, MAX_NUM_LIGHT_PIECES); m_defaultValueScaleSteps = num; } void KisColorSelector::setShowBgColor(bool value) { m_showBgColor = value; m_isDirtyColorPreview = true; update(); } void KisColorSelector::setShowValueScaleNumbers(bool value) { m_showValueScaleNumbers = value; recalculateAreas(quint8(getNumLightPieces())); update(); } diff --git a/plugins/dockers/artisticcolorselector/kis_color_selector.h b/plugins/dockers/artisticcolorselector/kis_color_selector.h index 30666fde44..5341c273d3 100644 --- a/plugins/dockers/artisticcolorselector/kis_color_selector.h +++ b/plugins/dockers/artisticcolorselector/kis_color_selector.h @@ -1,209 +1,209 @@ /* Copyright (C) 2011 Silvio Heinrich 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 H_KIS_COLOR_SELECTOR_H #define H_KIS_COLOR_SELECTOR_H #include #include #include #include #include "kis_color.h" #include "kis_radian.h" #include "kis_acs_types.h" #include "kis_signal_compressor_with_param.h" #include #include class QPainter; class KisDisplayColorConverter; class KisColorSelector: public QWidget { Q_OBJECT typedef KisRadian Radian; struct ColorRing { ColorRing() : saturation(0) , outerRadius(0) , innerRadius(0) { } qreal saturation; qreal outerRadius; qreal innerRadius; QVector pieced; }; public: KisColorSelector(QWidget* parent, KisColor::Type type=KisColor::HSL); void setColorSpace(KisColor::Type type); void setColorConverter(KisDisplayColorConverter* colorConverter); void setNumPieces(int num); void setNumLightPieces(int num) __attribute__((optimize(0))); void setNumRings(int num); void setLight(qreal light=0.0f); void setLumaCoefficients(qreal lR, qreal lG, qreal lB, qreal lGamma); inline qreal lumaR() const { return m_lumaR; } inline qreal lumaG() const { return m_lumaG; } inline qreal lumaB() const { return m_lumaB; } inline qreal lumaGamma() const { return m_lumaGamma; } void setInverseSaturation(bool inverse); void selectColor(const KisColor& color); void setFgColor(const KoColor& fgColor); void setBgColor(const KoColor& bgColor); void setDefaultHueSteps(int num); void setDefaultSaturationSteps(int num); void setDefaultValueScaleSteps(int num); void setShowBgColor(bool value); void setShowValueScaleNumbers(bool value); - void setGamutMask(KoGamutMask* gamutMask); + void setGamutMask(KoGamutMaskSP gamutMask); void setDirty(); bool gamutMaskOn(); void setGamutMaskOn(bool gamutMaskOn); void setEnforceGamutMask(bool enforce); - KoGamutMask* gamutMask(); + KoGamutMaskSP gamutMask(); void saveSettings(); void loadSettings(); KisColor::Type getColorSpace () const { return m_colorSpace; } qint32 getNumRings () const { return m_colorRings.size(); } qint32 getNumPieces () const { return m_numPieces; } qint32 getNumLightPieces () const { return m_numLightPieces; } bool isSaturationInverted() const { return m_inverseSaturation; } quint32 getDefaultHueSteps () const { return m_defaultHueSteps; } quint32 getDefaultSaturationSteps () const { return m_defaultSaturationSteps; } quint32 getDefaultValueScaleSteps () const { return m_defaultValueScaleSteps; } bool getShowBgColor () const { return m_showBgColor; } bool getShowValueScaleNumbers () const { return m_showValueScaleNumbers; } bool enforceGamutMask () const { return m_enforceGamutMask; } Q_SIGNALS: void sigFgColorChanged(const KisColor& color); void sigBgColorChanged(const KisColor& color); private: void mousePressEvent(QMouseEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override; void mouseReleaseEvent(QMouseEvent* event) override; void resizeEvent(QResizeEvent* event) override; void paintEvent(QPaintEvent* event) override; void leaveEvent(QEvent* e) override; bool colorIsClear(const KisColor &color); bool colorIsClear(const QPointF &colorPoint); void requestUpdateColorAndPreview(const KisColor &color, Acs::ColorRole role); void recalculateAreas(quint8 numLightPieces); void recalculateRings(quint8 numRings, quint8 numPieces); void createRing(ColorRing& wheel, quint8 numPieces, qreal innerRadius, qreal outerRadius); void drawRing(QPainter& painter, ColorRing& wheel, const QRect& rect); void drawOutline(QPainter& painter, const QRect& rect); void drawBlip(QPainter& painter, const QRect& rect); void drawLightStrip(QPainter& painter, const QRect& rect); void drawGamutMaskShape(QPainter& painter, const QRect& rect); void drawColorPreview(QPainter& painter, const QRect& rect); qint8 getHueIndex(Radian hue) const; qreal getHue(int hueIdx, Radian shift=0.0f) const; qint8 getLightIndex(const QPointF& pt) const; qint8 getLightIndex(qreal light) const; qreal getLight(const QPointF& pt) const; qint8 getSaturationIndex(const QPointF& pt) const; qint8 getSaturationIndex(qreal saturation) const; qreal getSaturation(int saturationIdx) const; QPointF mapCoordToView(const QPointF& pt, const QRectF& viewRect) const; QPointF mapCoordToUnit(const QPointF& pt, const QRectF& viewRect) const; QPointF mapColorToUnit(const KisColor& color, bool invertSaturation = true) const; Radian mapCoordToAngle(qreal x, qreal y) const; QPointF mapHueToAngle(qreal hue) const; public: // This is a private interface for signal compressor, don't use it. // Use requestUpdateColorAndPreview() instead void slotUpdateColorAndPreview(QPair color); private: KisDisplayColorConverter* m_colorConverter; KisColor::Type m_colorSpace; quint8 m_numPieces; quint8 m_numLightPieces; bool m_inverseSaturation; qint8 m_selectedRing; qint8 m_selectedPiece; qint8 m_selectedLightPiece; KisColor m_selectedColor; KisColor m_fgColor; KisColor m_bgColor; QImage m_renderBuffer; QImage m_maskBuffer; QImage m_lightStripBuffer; QImage m_colorPreviewBuffer; QRect m_widgetArea; QRect m_renderArea; QRect m_lightStripArea; bool m_mouseMoved; QPointF m_clickPos; qint8 m_clickedRing; QVector m_colorRings; Qt::MouseButtons m_pressedButtons; // docker settings quint8 m_defaultHueSteps; quint8 m_defaultSaturationSteps; quint8 m_defaultValueScaleSteps; bool m_showValueScaleNumbers; bool m_showBgColor; bool m_gamutMaskOn; - KoGamutMask* m_currentGamutMask; + KoGamutMaskSP m_currentGamutMask; bool m_enforceGamutMask; QSize m_renderAreaSize; bool m_maskPreviewActive; KisGamutMaskViewConverter* m_viewConverter; bool m_widgetUpdatesSelf; bool m_isDirtyWheel; bool m_isDirtyLightStrip; bool m_isDirtyGamutMask; bool m_isDirtyColorPreview; qreal m_lumaR; qreal m_lumaG; qreal m_lumaB; qreal m_lumaGamma; typedef KisSignalCompressorWithParam> ColorCompressorType; QScopedPointer m_updateColorCompressor; }; #endif // H_KIS_COLOR_SELECTOR_H diff --git a/plugins/dockers/gamutmask/KisGamutMaskChooser.cpp b/plugins/dockers/gamutmask/KisGamutMaskChooser.cpp index 19cf385cc7..5085bbf887 100644 --- a/plugins/dockers/gamutmask/KisGamutMaskChooser.cpp +++ b/plugins/dockers/gamutmask/KisGamutMaskChooser.cpp @@ -1,251 +1,252 @@ /* * Copyright (c) 2018 Anna Medonosova * * 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; version 2.1 of the License. * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisGamutMaskChooser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /// The resource item delegate for rendering the resource preview class KisGamutMaskDelegate: public QAbstractItemDelegate { public: KisGamutMaskDelegate(QObject * parent = 0) : QAbstractItemDelegate(parent) , m_mode(KisGamutMaskChooser::ViewMode::THUMBNAIL) {} ~KisGamutMaskDelegate() override {} /// reimplemented void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override; /// reimplemented QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex &) const override { return option.decorationSize; } void setViewMode(KisGamutMaskChooser::ViewMode mode) { m_mode = mode; } private: KisGamutMaskChooser::ViewMode m_mode; }; void KisGamutMaskDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { painter->save(); painter->setRenderHint(QPainter::SmoothPixmapTransform, true); if (!index.isValid()) return; - KoResource* resource = static_cast(index.internalPointer()); - KoGamutMask* mask = static_cast(resource); + KoResourceSP resource = KoResourceSP(static_cast(index.internalPointer())); + + KoGamutMaskSP mask = resource.staticCast(); if (!mask) { return; } QImage preview = mask->image(); if(preview.isNull()) { return; } QRect paintRect = option.rect.adjusted(1, 1, -1, -1); if (m_mode == KisGamutMaskChooser::ViewMode::THUMBNAIL) { painter->drawImage(paintRect.x(), paintRect.y(), preview.scaled(paintRect.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); if (option.state & QStyle::State_Selected) { painter->setCompositionMode(QPainter::CompositionMode_Overlay); painter->setOpacity(0.5); painter->fillRect(paintRect, Qt::white); painter->setCompositionMode(QPainter::CompositionMode_SourceOver); painter->setOpacity(1.0); painter->setPen(QPen(option.palette.highlight(), 2, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin)); QRect selectedBorder = option.rect.adjusted(1, 1, -1, -1); painter->drawRect(selectedBorder); } } else { QSize previewSize(paintRect.height(), paintRect.height()); painter->drawImage(paintRect.x(), paintRect.y(), preview.scaled(previewSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); int leftMargin = 8; int rightMargin = 7; int vertMargin = 4; int descOffset = 7; QFont font = option.font; font.setBold(true); painter->setFont(font); QRectF titleRect(QPointF(previewSize.width() + leftMargin, paintRect.y() + vertMargin), QPointF(paintRect.width() - rightMargin, paintRect.y() + descOffset + painter->fontMetrics().lineSpacing())); painter->drawText(titleRect, Qt::AlignLeft, painter->fontMetrics().elidedText( mask->title(), Qt::ElideRight, titleRect.width() ) ); if (!mask->description().isEmpty() && !mask->description().isNull()) { font.setPointSize(font.pointSize()-1); font.setBold(false); font.setStyle(QFont::StyleItalic); painter->setFont(font); QRectF descRect(QPointF(previewSize.width() + leftMargin, paintRect.y() + descOffset + painter->fontMetrics().lineSpacing()), QPointF(paintRect.right() - rightMargin, paintRect.bottom() - vertMargin)); int numLines = floor(((float)descRect.height() / (float)painter->fontMetrics().lineSpacing())); if (numLines > 0) { int elideWidth = 0; QTextLayout textLayout(mask->description()); textLayout.beginLayout(); for (int i = 0; i < numLines; i++) { QTextLine line = textLayout.createLine(); if (line.isValid()) { line.setLineWidth(descRect.width()); elideWidth += line.naturalTextWidth(); } } QString elidedText = painter->fontMetrics().elidedText(mask->description(), Qt::ElideRight, elideWidth); painter->drawText(descRect, Qt::AlignLeft|Qt::TextWordWrap, elidedText); } } } painter->restore(); } KisGamutMaskChooser::KisGamutMaskChooser(QWidget *parent) : QWidget(parent) { m_delegate = new KisGamutMaskDelegate(this); KoResourceServer* rServer = KoResourceServerProvider::instance()->gamutMaskServer(); QSharedPointer adapter(new KoResourceServerAdapter(rServer)); m_itemChooser = new KoResourceItemChooser(adapter, this); m_itemChooser->setItemDelegate(m_delegate); m_itemChooser->showTaggingBar(true); m_itemChooser->showButtons(false); m_itemChooser->setColumnCount(4); m_itemChooser->setSynced(true); QVBoxLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(0,0,0,0); // TODO: menu for view mode change QMenu* menu = new QMenu(this); menu->setStyleSheet("margin: 6px"); menu->addSection(i18n("Display")); QActionGroup *actionGroup = new QActionGroup(this); KisConfig cfg(true); m_mode = KisGamutMaskChooser::ViewMode(cfg.readEntry("GamutMasks.viewMode", KisGamutMaskChooser::THUMBNAIL)); QAction* action = menu->addAction(KisIconUtils::loadIcon("view-preview"), i18n("Thumbnails"), this, SLOT(slotSetModeThumbnail())); action->setCheckable(true); action->setChecked(m_mode == KisGamutMaskChooser::THUMBNAIL); action->setActionGroup(actionGroup); action = menu->addAction(KisIconUtils::loadIcon("view-list-details"), i18n("Details"), this, SLOT(slotSetModeDetail())); action->setCheckable(true); action->setChecked(m_mode == KisGamutMaskChooser::DETAIL); action->setActionGroup(actionGroup); // setting the view mode setViewMode(m_mode); m_itemChooser->setViewModeButtonVisible(true); QToolButton* viewModeButton = m_itemChooser->viewModeButton(); viewModeButton->setMenu(menu); layout->addWidget(m_itemChooser); setLayout(layout); - connect(m_itemChooser, SIGNAL(resourceSelected(KoResource*)), this, SLOT(resourceSelected(KoResource*))); + connect(m_itemChooser, SIGNAL(resourceSelected(KoResourceSP )), this, SLOT(resourceSelected(KoResourceSP ))); } KisGamutMaskChooser::~KisGamutMaskChooser() { } -void KisGamutMaskChooser::setCurrentResource(KoResource *resource) +void KisGamutMaskChooser::setCurrentResource(KoResourceSP resource) { m_itemChooser->setCurrentResource(resource); } void KisGamutMaskChooser::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); updateViewSettings(); } void KisGamutMaskChooser::setViewMode(KisGamutMaskChooser::ViewMode mode) { m_mode = mode; updateViewSettings(); } void KisGamutMaskChooser::updateViewSettings() { KisConfig cfg(false); cfg.writeEntry("GamutMasks.viewMode", qint32(m_mode)); if (m_mode == KisGamutMaskChooser::THUMBNAIL) { m_itemChooser->setSynced(true); m_delegate->setViewMode(m_mode); } else if (m_mode == KisGamutMaskChooser::DETAIL) { m_itemChooser->setSynced(false); m_itemChooser->setColumnCount(1); m_itemChooser->setRowHeight(this->fontMetrics().lineSpacing()*4); m_itemChooser->setColumnWidth(m_itemChooser->width()); m_delegate->setViewMode(m_mode); } } -void KisGamutMaskChooser::resourceSelected(KoResource* resource) +void KisGamutMaskChooser::resourceSelected(KoResourceSP resource) { - emit sigGamutMaskSelected(static_cast(resource)); + emit sigGamutMaskSelected(resource.staticCast()); } void KisGamutMaskChooser::slotSetModeThumbnail() { setViewMode(KisGamutMaskChooser::THUMBNAIL); } void KisGamutMaskChooser::slotSetModeDetail() { setViewMode(KisGamutMaskChooser::DETAIL); } diff --git a/plugins/dockers/gamutmask/KisGamutMaskChooser.h b/plugins/dockers/gamutmask/KisGamutMaskChooser.h index 7ed187b96c..c0870a126c 100644 --- a/plugins/dockers/gamutmask/KisGamutMaskChooser.h +++ b/plugins/dockers/gamutmask/KisGamutMaskChooser.h @@ -1,61 +1,62 @@ /* * Copyright (c) 2018 Anna Medonosova * * 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; version 2.1 of the License. * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KISGAMUTMASKCHOOSER_H #define KISGAMUTMASKCHOOSER_H #include class KoResourceItemChooser; -class KoResource; -class KoGamutMask; +#include +#include + class KisGamutMaskDelegate; class KisGamutMaskChooser : public QWidget { Q_OBJECT public: explicit KisGamutMaskChooser(QWidget *parent = nullptr); ~KisGamutMaskChooser() override; enum ViewMode { THUMBNAIL, // Shows thumbnails DETAIL // Shows thumbsnails with text next to it }; - void setCurrentResource(KoResource* resource); + void setCurrentResource(KoResourceSP resource); protected: void resizeEvent(QResizeEvent* event) override; Q_SIGNALS: - void sigGamutMaskSelected(KoGamutMask* mask); + void sigGamutMaskSelected(KoGamutMaskSP mask); private Q_SLOTS: - void resourceSelected(KoResource* resource); + void resourceSelected(KoResourceSP resource); void slotSetModeThumbnail(); void slotSetModeDetail(); private: void setViewMode(ViewMode mode); void updateViewSettings(); KoResourceItemChooser* m_itemChooser; KisGamutMaskDelegate* m_delegate; ViewMode m_mode; }; #endif // KISGAMUTMASKCHOOSER_H diff --git a/plugins/dockers/gamutmask/gamutmask_dock.cpp b/plugins/dockers/gamutmask/gamutmask_dock.cpp index b4b5b6a89a..c5bdb6326e 100644 --- a/plugins/dockers/gamutmask/gamutmask_dock.cpp +++ b/plugins/dockers/gamutmask/gamutmask_dock.cpp @@ -1,629 +1,629 @@ /* * Copyright (c) 2018 Anna Medonosova * * 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; version 2.1 of the License. * * 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 program; 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gamutmask_dock.h" #include #include #include #include #include #include "ui_wdgGamutMaskChooser.h" class KisMainWindow; struct GamutMaskChooserUI: public QWidget, public Ui_wdgGamutMaskChooser { GamutMaskChooserUI() { setupUi(this); } }; GamutMaskDock::GamutMaskDock() : QDockWidget(i18n("Gamut Masks")) , m_resourceProvider(0) , m_selfClosingTemplate(false) , m_externalTemplateClose(false) , m_creatingNewMask(false) , m_templatePrevSaved(false) , m_selfSelectingMask(false) , m_selectedMask(nullptr) , m_maskDocument(nullptr) , m_view(nullptr) { m_dockerUI = new GamutMaskChooserUI(); m_dockerUI->bnMaskEditor->setIcon(KisIconUtils::loadIcon("dirty-preset")); m_dockerUI->bnMaskDelete->setIcon(KisIconUtils::loadIcon("deletelayer")); m_dockerUI->bnMaskNew->setIcon(KisIconUtils::loadIcon("list-add")); m_dockerUI->bnMaskDuplicate->setIcon(KisIconUtils::loadIcon("duplicatelayer")); m_dockerUI->maskPropertiesBox->setVisible(false); m_dockerUI->bnSaveMask->setIcon(KisIconUtils::loadIcon("document-save")); m_dockerUI->bnCancelMaskEdit->setIcon(KisIconUtils::loadIcon("dialog-cancel")); m_dockerUI->bnPreviewMask->setIcon(KisIconUtils::loadIcon("visible")); QRegularExpression maskTitleRegex("^[-_\\(\\)\\sA-Za-z0-9]+$"); QRegularExpressionValidator* m_maskTitleValidator = new QRegularExpressionValidator(maskTitleRegex, this); m_dockerUI->maskTitleEdit->setValidator(m_maskTitleValidator); KoResourceServer* rServer = KoResourceServerProvider::instance()->gamutMaskServer(); rServer->addObserver(this); // gamut mask connections connect(m_dockerUI->bnSaveMask , SIGNAL(clicked()) , SLOT(slotGamutMaskSave())); connect(m_dockerUI->bnCancelMaskEdit , SIGNAL(clicked()) , SLOT(slotGamutMaskCancelEdit())); connect(m_dockerUI->bnPreviewMask , SIGNAL(clicked()) , SLOT(slotGamutMaskPreview())); connect(m_dockerUI->bnMaskEditor , SIGNAL(clicked()) , SLOT(slotGamutMaskEdit())); - connect(m_dockerUI->maskChooser, SIGNAL(sigGamutMaskSelected(KoGamutMask*)), SLOT(slotGamutMaskSelected(KoGamutMask*))); + connect(m_dockerUI->maskChooser, SIGNAL(sigGamutMaskSelected(KoGamutMaskSP)), SLOT(slotGamutMaskSelected(KoGamutMaskSP))); connect(m_dockerUI->bnMaskNew , SIGNAL(clicked()) , SLOT(slotGamutMaskCreateNew())); connect(m_dockerUI->bnMaskDelete , SIGNAL(clicked()) , SLOT(slotGamutMaskDelete())); connect(m_dockerUI->bnMaskDuplicate , SIGNAL(clicked()) , SLOT(slotGamutMaskDuplicate())); setWidget(m_dockerUI); } GamutMaskDock::~GamutMaskDock() { KoResourceServer* rServer = KoResourceServerProvider::instance()->gamutMaskServer(); rServer->removeObserver(this); } void GamutMaskDock::setViewManager(KisViewManager* kisview) { m_resourceProvider = kisview->resourceProvider(); selectMask(m_resourceProvider->currentGamutMask()); - connect(this, SIGNAL(sigGamutMaskSet(KoGamutMask*)), m_resourceProvider, SLOT(slotGamutMaskActivated(KoGamutMask*))); - connect(this, SIGNAL(sigGamutMaskChanged(KoGamutMask*)), m_resourceProvider, SLOT(slotGamutMaskActivated(KoGamutMask*))); + connect(this, SIGNAL(sigGamutMaskSet(KoGamutMaskSP)), m_resourceProvider, SLOT(slotGamutMaskActivated(KoGamutMaskSP))); + connect(this, SIGNAL(sigGamutMaskChanged(KoGamutMaskSP)), m_resourceProvider, SLOT(slotGamutMaskActivated(KoGamutMaskSP))); connect(this, SIGNAL(sigGamutMaskUnset()), m_resourceProvider, SLOT(slotGamutMaskUnset())); connect(this, SIGNAL(sigGamutMaskPreviewUpdate()), m_resourceProvider, SLOT(slotGamutMaskPreviewUpdate())); connect(KisPart::instance(), SIGNAL(sigDocumentRemoved(QString)), this, SLOT(slotDocumentRemoved(QString))); } void GamutMaskDock::slotGamutMaskEdit() { if (!m_selectedMask) { return; } openMaskEditor(); } bool GamutMaskDock::openMaskEditor() { if (!m_selectedMask) { return false; } // find the template resource first, so we can abort the action early on QString maskTemplateFile = KoResourcePaths::findResource("gamutmasks", "GamutMaskTemplate.kra"); if (maskTemplateFile.isEmpty() || maskTemplateFile.isNull() || !QFile::exists(maskTemplateFile)) { dbgPlugins << "GamutMaskDock::openMaskEditor(): maskTemplateFile (" << maskTemplateFile << ") was not found on the system"; getUserFeedback(i18n("Could not open gamut mask for editing."), i18n("The editor template was not found."), QMessageBox::Ok, QMessageBox::Ok, QMessageBox::Critical); return false; } m_dockerUI->maskPropertiesBox->setVisible(true); m_dockerUI->maskPropertiesBox->setEnabled(true); m_dockerUI->editControlsBox->setEnabled(false); m_dockerUI->editControlsBox->setVisible(false); m_dockerUI->maskTitleEdit->setText(m_selectedMask->title()); m_dockerUI->maskDescriptionEdit->setPlainText(m_selectedMask->description()); m_maskDocument = KisPart::instance()->createDocument(); KisPart::instance()->addDocument(m_maskDocument); m_maskDocument->openUrl(QUrl::fromLocalFile(maskTemplateFile), KisDocument::DontAddToRecent); // template document needs a proper autogenerated filename, // to avoid collision with other documents, // otherwise bugs happen when slotDocumentRemoved is called // (e.g. user closes another view, the template stays open, but the edit operation is canceled) m_maskDocument->setInfiniteAutoSaveInterval(); QString maskPath = QString("%1%2%3_%4.kra") .arg(QDir::tempPath()) .arg(QDir::separator()) .arg("GamutMaskTemplate") .arg(std::time(nullptr)); m_maskDocument->setUrl(QUrl::fromLocalFile(maskPath)); m_maskDocument->setLocalFilePath(maskPath); KisShapeLayerSP shapeLayer = getShapeLayer(); // pass only copies of shapes to the layer, // so the originals don't disappear from the mask later for (KoShape *shape: m_selectedMask->koShapes()) { KoShape* newShape = shape->cloneShape(); newShape->setStroke(KoShapeStrokeModelSP()); newShape->setBackground(QSharedPointer(new KoColorBackground(QColor(255,255,255)))); shapeLayer->addShape(newShape); } m_maskDocument->setPreActivatedNode(shapeLayer); // set document as active KisMainWindow* mainWindow = KisPart::instance()->currentMainwindow(); KIS_ASSERT(mainWindow); m_view = mainWindow->addViewAndNotifyLoadingCompleted(m_maskDocument); KIS_ASSERT(m_view); for(KisView *view: KisPart::instance()->views()) { if (view->document() == m_maskDocument) { view->activateWindow(); break; } } connect(m_view->viewManager(), SIGNAL(viewChanged()), this, SLOT(slotViewChanged())); connect(m_maskDocument, SIGNAL(completed()), this, SLOT(slotDocumentSaved())); return true; } void GamutMaskDock::cancelMaskEdit() { if (m_creatingNewMask) { deleteMask(); } if (m_selectedMask) { m_selectedMask->clearPreview(); if (m_resourceProvider->currentGamutMask() == m_selectedMask) { emit sigGamutMaskChanged(m_selectedMask); } } closeMaskDocument(); } -void GamutMaskDock::selectMask(KoGamutMask *mask, bool notifyItemChooser) +void GamutMaskDock::selectMask(KoGamutMaskSP mask, bool notifyItemChooser) { if (!mask) { return; } m_selectedMask = mask; if (notifyItemChooser) { m_selfSelectingMask = true; m_dockerUI->maskChooser->setCurrentResource(m_selectedMask); m_selfSelectingMask = false; } emit sigGamutMaskSet(m_selectedMask); } bool GamutMaskDock::saveSelectedMaskResource() { if (!m_selectedMask || !m_maskDocument) { return false; } bool maskSaved = false; if (m_selectedMask) { QList shapes = getShapesFromLayer(); if (shapes.count() > 0) { m_selectedMask->setMaskShapes(shapes); m_selectedMask->setImage( m_maskDocument->image()->convertToQImage(m_maskDocument->image()->bounds() , m_maskDocument->image()->profile() ) ); m_selectedMask->setDescription(m_dockerUI->maskDescriptionEdit->toPlainText()); m_selectedMask->clearPreview(); m_selectedMask->save(); maskSaved = true; } else { getUserFeedback(i18n("Saving of gamut mask '%1' was aborted.", m_selectedMask->title()), i18n("

    The mask template is invalid.

    " "

    Please check that:" "

      " "
    • your template contains a vector layer named 'maskShapesLayer'
    • " "
    • there are one or more vector shapes on the 'maskShapesLayer'
    • " "

    " ), QMessageBox::Ok, QMessageBox::Ok); } } return maskSaved; } void GamutMaskDock::deleteMask() { KoResourceServer* rServer = KoResourceServerProvider::instance()->gamutMaskServer(); rServer->removeResourceAndBlacklist(m_selectedMask); m_selectedMask = nullptr; } int GamutMaskDock::getUserFeedback(QString text, QString informativeText, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton, QMessageBox::Icon severity) { QMessageBox msgBox; msgBox.setWindowTitle(i18nc("@title:window", "Krita")); msgBox.setText(QString("

    %1

    ").arg(text)); msgBox.setInformativeText(informativeText); msgBox.setStandardButtons(buttons); msgBox.setDefaultButton(defaultButton); msgBox.setIcon(severity); int res = msgBox.exec(); return res; } int GamutMaskDock::saveOrCancel(QMessageBox::StandardButton defaultAction) { int response = 0; if (m_maskDocument->isModified()) { response = getUserFeedback(i18n("Gamut mask '%1' has been modified.", m_selectedMask->title()), i18n("Do you want to save it?"), QMessageBox::Cancel | QMessageBox::Close | QMessageBox::Save, defaultAction); } else if (m_templatePrevSaved && defaultAction != QMessageBox::Close) { response = QMessageBox::Save; } else if (!m_templatePrevSaved) { response = QMessageBox::Close; } else { response = defaultAction; } switch (response) { case QMessageBox::Save : { slotGamutMaskSave(); break; } case QMessageBox::Close : { cancelMaskEdit(); break; } } return response; } -KoGamutMask *GamutMaskDock::createMaskResource(KoGamutMask* sourceMask, QString newTitle) +KoGamutMaskSP GamutMaskDock::createMaskResource(KoGamutMaskSP sourceMask, QString newTitle) { m_creatingNewMask = true; - KoGamutMask* newMask = nullptr; + KoGamutMaskSP newMask; if (sourceMask) { - newMask = new KoGamutMask(sourceMask); + newMask = KoGamutMaskSP(new KoGamutMask(sourceMask.data())); newMask->setImage(sourceMask->image()); } else { - newMask = new KoGamutMask(); + newMask = KoGamutMaskSP(new KoGamutMask()); QString defaultPreviewPath = KoResourcePaths::findResource("gamutmasks", "empty_mask_preview.png"); KIS_SAFE_ASSERT_RECOVER_NOOP(!(defaultPreviewPath.isEmpty() || defaultPreviewPath.isNull() || !QFile::exists(defaultPreviewPath))); newMask->setImage(QImage(defaultPreviewPath, "PNG")); } QPair maskFile = resolveMaskTitle(newTitle); QString maskTitle = maskFile.first; QFileInfo fileInfo = maskFile.second; newMask->setTitle(maskTitle); newMask->setFilename(fileInfo.filePath()); newMask->setValid(true); KoResourceServer* rServer = KoResourceServerProvider::instance()->gamutMaskServer(); rServer->removeFromBlacklist(newMask); rServer->addResource(newMask, false); return newMask; } QPair GamutMaskDock::resolveMaskTitle(QString suggestedTitle) { KoResourceServer* rServer = KoResourceServerProvider::instance()->gamutMaskServer(); QString saveLocation = rServer->saveLocation(); QString processedTitle = suggestedTitle.trimmed(); QString resourceName = processedTitle; while (rServer->resourceByName(resourceName)) { resourceName = resourceName + QString(" (Copy)"); } QString maskTitle = resourceName; QString maskFile = maskTitle + ".kgm"; QString path = saveLocation + maskFile.replace(QRegularExpression("\\s+"), "_"); QFileInfo fileInfo(path); return QPair(maskTitle, fileInfo); } void GamutMaskDock::closeMaskDocument() { if (!m_externalTemplateClose) { if (m_maskDocument) { // set the document to not modified to bypass confirmation dialog // the close is already confirmed m_maskDocument->setModified(false); m_maskDocument->closeUrl(); m_view->closeView(); m_view->deleteLater(); // set a flag that we are doing it ourselves, so the docker does not react to // removing signal from KisPart m_selfClosingTemplate = true; KisPart::instance()->removeView(m_view); KisPart::instance()->removeDocument(m_maskDocument); m_selfClosingTemplate = false; } } m_dockerUI->maskPropertiesBox->setVisible(false); m_dockerUI->editControlsBox->setVisible(true); m_dockerUI->editControlsBox->setEnabled(true); disconnect(m_view->viewManager(), SIGNAL(viewChanged()), this, SLOT(slotViewChanged())); disconnect(m_maskDocument, SIGNAL(completed()), this, SLOT(slotDocumentSaved())); // the template file is meant as temporary, if the user saved it, delete now if (QFile::exists(m_maskDocument->localFilePath())) { QFile::remove(m_maskDocument->localFilePath()); } m_maskDocument = nullptr; m_view = nullptr; m_creatingNewMask = false; m_templatePrevSaved = false; } QList GamutMaskDock::getShapesFromLayer() { KisShapeLayerSP shapeLayer = getShapeLayer(); // create a deep copy of the shapes to save in the mask, // otherwise they vanish when the template closes QList newShapes; if (shapeLayer) { for (KoShape* sh: shapeLayer->shapes()) { KoShape* newShape = sh->cloneShape(); KoShapeStrokeSP border(new KoShapeStroke(0.5f, Qt::white)); newShape->setStroke(border); newShape->setBackground(QSharedPointer(new KoColorBackground(QColor(255,255,255,0)))); newShapes.append(newShape); } } return newShapes; } KisShapeLayerSP GamutMaskDock::getShapeLayer() { KisNodeSP node = m_maskDocument->image()->rootLayer()->findChildByName("maskShapesLayer"); return KisShapeLayerSP(dynamic_cast(node.data())); } void GamutMaskDock::slotGamutMaskSave() { if (!m_selectedMask || !m_maskDocument) { return; } QString newTitle = m_dockerUI->maskTitleEdit->text(); if (m_selectedMask->title() != newTitle) { // title has changed, rename - KoGamutMask* newMask = createMaskResource(m_selectedMask, newTitle); + KoGamutMaskSP newMask = createMaskResource(m_selectedMask, newTitle); // delete old mask and select new deleteMask(); selectMask(newMask); } bool maskSaved = saveSelectedMaskResource(); if (maskSaved) { emit sigGamutMaskSet(m_selectedMask); closeMaskDocument(); } } void GamutMaskDock::slotGamutMaskCancelEdit() { if (!m_selectedMask) { return; } saveOrCancel(QMessageBox::Close); } void GamutMaskDock::slotGamutMaskPreview() { if (!m_selectedMask) { return; } m_selectedMask->setPreviewMaskShapes(getShapesFromLayer()); emit sigGamutMaskPreviewUpdate(); } -void GamutMaskDock::slotGamutMaskSelected(KoGamutMask *mask) +void GamutMaskDock::slotGamutMaskSelected(KoGamutMaskSP mask) { if (!m_selfSelectingMask) { if (m_maskDocument) { int res = saveOrCancel(); if (res == QMessageBox::Cancel) { return; } } selectMask(mask, false); } } void GamutMaskDock::setCanvas(KoCanvasBase *canvas) { setEnabled(canvas != 0); } void GamutMaskDock::unsetCanvas() { setEnabled(false); } void GamutMaskDock::unsetResourceServer() { KoResourceServer* rServer = KoResourceServerProvider::instance()->gamutMaskServer(); rServer->removeObserver(this); } -void GamutMaskDock::removingResource(KoGamutMask *resource) +void GamutMaskDock::removingResource(KoGamutMaskSP resource) { // if deleting previously set mask, notify selectors to unset their mask if (resource == m_resourceProvider->currentGamutMask()) { emit sigGamutMaskUnset(); m_selectedMask = nullptr; } } -void GamutMaskDock::resourceChanged(KoGamutMask *resource) +void GamutMaskDock::resourceChanged(KoGamutMaskSP resource) { // if currently set mask has been changed, notify selectors if (resource == m_resourceProvider->currentGamutMask()) { selectMask(resource); } } void GamutMaskDock::slotGamutMaskCreateNew() { - KoGamutMask* newMask = createMaskResource(nullptr, "new mask"); + KoGamutMaskSP newMask = createMaskResource(nullptr, "new mask"); selectMask(newMask); bool editorOpened = openMaskEditor(); if (!editorOpened) { deleteMask(); } } void GamutMaskDock::slotGamutMaskDuplicate() { if (!m_selectedMask) { return; } - KoGamutMask* newMask = createMaskResource(m_selectedMask, m_selectedMask->title()); + KoGamutMaskSP newMask = createMaskResource(m_selectedMask, m_selectedMask->title()); selectMask(newMask); bool editorOpened = openMaskEditor(); if (!editorOpened) { deleteMask(); } } void GamutMaskDock::slotGamutMaskDelete() { if (!m_selectedMask) { return; } int res = getUserFeedback(i18n("Are you sure you want to delete mask '%1'?" , m_selectedMask->title())); if (res == QMessageBox::Yes) { deleteMask(); } } void GamutMaskDock::slotDocumentRemoved(QString filename) { if (!m_maskDocument) { return; } m_externalTemplateClose = true; // we do not want to run this if it is we who close the file if (!m_selfClosingTemplate) { // KisPart called, that a document will be removed // if it's ours, cancel the mask edit operation if (m_maskDocument->url().toLocalFile() == filename) { m_maskDocument->waitForSavingToComplete(); saveOrCancel(); } } m_externalTemplateClose = false; } void GamutMaskDock::slotViewChanged() { if (!m_maskDocument || !m_view) { return; } if (m_view->viewManager()->document() == m_maskDocument) { m_dockerUI->maskPropertiesBox->setEnabled(true); } else { m_dockerUI->maskPropertiesBox->setEnabled(false); } } void GamutMaskDock::slotDocumentSaved() { m_templatePrevSaved = true; } diff --git a/plugins/dockers/gamutmask/gamutmask_dock.h b/plugins/dockers/gamutmask/gamutmask_dock.h index 43e14d0af7..de86d2d17e 100644 --- a/plugins/dockers/gamutmask/gamutmask_dock.h +++ b/plugins/dockers/gamutmask/gamutmask_dock.h @@ -1,125 +1,125 @@ /* * Copyright (c) 2018 Anna Medonosova * * 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; version 2.1 of the License. * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef H_GAMUT_MASK_DOCK_H #define H_GAMUT_MASK_DOCK_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include class KisCanvasResourceProvider; class QButtonGroup; class QMenu; struct GamutMaskChooserUI; class GamutMaskDock: public QDockWidget, public KisMainwindowObserver, public KoResourceServerObserver { Q_OBJECT public: GamutMaskDock(); ~GamutMaskDock() override; QString observerName() override { return "GamutMaskDock"; } void setViewManager(KisViewManager* kisview) override; void setCanvas(KoCanvasBase *canvas) override; void unsetCanvas() override; public: // KoResourceServerObserver void unsetResourceServer() override; - void resourceAdded(KoGamutMask* /*resource*/) override {}; - void removingResource(KoGamutMask* resource) override; - void resourceChanged(KoGamutMask* resource) override; + void resourceAdded(KoGamutMaskSP /*resource*/) override {} + void removingResource(KoGamutMaskSP resource) override; + void resourceChanged(KoGamutMaskSP resource) override; void syncTaggedResourceView() override {} void syncTagAddition(const QString&) override {} void syncTagRemoval(const QString&) override {} Q_SIGNALS: - void sigGamutMaskSet(KoGamutMask* mask); - void sigGamutMaskChanged(KoGamutMask* mask); + void sigGamutMaskSet(KoGamutMaskSP mask); + void sigGamutMaskChanged(KoGamutMaskSP mask); void sigGamutMaskUnset(); void sigGamutMaskPreviewUpdate(); private Q_SLOTS: void slotGamutMaskEdit(); void slotGamutMaskSave(); void slotGamutMaskCancelEdit(); - void slotGamutMaskSelected(KoGamutMask* mask); + void slotGamutMaskSelected(KoGamutMaskSP mask); void slotGamutMaskPreview(); void slotGamutMaskCreateNew(); void slotGamutMaskDuplicate(); void slotGamutMaskDelete(); void slotDocumentRemoved(QString filename); void slotViewChanged(); void slotDocumentSaved(); private: void closeMaskDocument(); bool openMaskEditor(); void cancelMaskEdit(); - void selectMask(KoGamutMask* mask, bool notifyItemChooser = true); + void selectMask(KoGamutMaskSP mask, bool notifyItemChooser = true); bool saveSelectedMaskResource(); void deleteMask(); int getUserFeedback(QString text, QString informativeText = "", QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No, QMessageBox::StandardButton defaultButton = QMessageBox::Yes, QMessageBox::Icon severity = QMessageBox::Warning); int saveOrCancel(QMessageBox::StandardButton defaultAction = QMessageBox::Save); - KoGamutMask* createMaskResource(KoGamutMask* sourceMask, QString newTitle); + KoGamutMaskSP createMaskResource(KoGamutMaskSP sourceMask, QString newTitle); QPair resolveMaskTitle(QString suggestedTitle); QList getShapesFromLayer(); KisShapeLayerSP getShapeLayer(); KisCanvasResourceProvider* m_resourceProvider; bool m_selfClosingTemplate; bool m_externalTemplateClose; bool m_creatingNewMask; bool m_templatePrevSaved; bool m_selfSelectingMask; GamutMaskChooserUI* m_dockerUI; KoResourceItemChooser* m_maskChooser; - KoGamutMask* m_selectedMask; + KoGamutMaskSP m_selectedMask; QRegExpValidator* m_maskTitleValidator; KisDocument* m_maskDocument; KisView* m_view; }; #endif // H_GAMUT_MASK_DOCK_H diff --git a/plugins/dockers/palettedocker/palettedocker_dock.cpp b/plugins/dockers/palettedocker/palettedocker_dock.cpp index 386c23b24c..7061cf45ea 100644 --- a/plugins/dockers/palettedocker/palettedocker_dock.cpp +++ b/plugins/dockers/palettedocker/palettedocker_dock.cpp @@ -1,371 +1,371 @@ /* * Copyright (c) 2013 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 "palettedocker_dock.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ui_wdgpalettedock.h" PaletteDockerDock::PaletteDockerDock( ) : QDockWidget(i18n("Palette")) , m_ui(new Ui_WdgPaletteDock()) , m_model(new KisPaletteModel(this)) , m_paletteChooser(new KisPaletteListWidget(this)) , m_view(Q_NULLPTR) , m_resourceProvider(Q_NULLPTR) , m_rServer(KoResourceServerProvider::instance()->paletteServer()) , m_activeDocument(Q_NULLPTR) , m_paletteEditor(new KisPaletteEditor) , m_actAdd(new QAction(KisIconUtils::loadIcon("list-add"), i18n("Add a color"))) , m_actRemove(new QAction(KisIconUtils::loadIcon("edit-delete"), i18n("Delete color"))) , m_actModify(new QAction(KisIconUtils::loadIcon("edit-rename"), i18n("Modify this spot"))) , m_actEditPalette(new QAction(KisIconUtils::loadIcon("groupLayer"), i18n("Edit this palette"))) { QWidget *mainWidget = new QWidget(this); setWidget(mainWidget); m_ui->setupUi(mainWidget); m_ui->bnAdd->setDefaultAction(m_actAdd.data()); m_ui->bnRemove->setDefaultAction(m_actRemove.data()); m_ui->bnRename->setDefaultAction(m_actModify.data()); m_ui->bnEditPalette->setDefaultAction(m_actEditPalette.data()); // to make sure their icons have the same size m_ui->bnRemove->setIconSize(QSize(16, 16)); m_ui->bnRename->setIconSize(QSize(16, 16)); m_ui->bnAdd->setIconSize(QSize(16, 16)); m_ui->bnEditPalette->setIconSize(QSize(16, 16)); m_ui->paletteView->setPaletteModel(m_model); m_ui->paletteView->setAllowModification(true); m_ui->cmbNameList->setCompanionView(m_ui->paletteView); m_paletteEditor->setPaletteModel(m_model); connect(m_actAdd.data(), SIGNAL(triggered()), SLOT(slotAddColor())); connect(m_actRemove.data(), SIGNAL(triggered()), SLOT(slotRemoveColor())); connect(m_actModify.data(), SIGNAL(triggered()), SLOT(slotEditEntry())); connect(m_actEditPalette.data(), SIGNAL(triggered()), SLOT(slotEditPalette())); connect(m_ui->paletteView, SIGNAL(sigIndexSelected(QModelIndex)), SLOT(slotPaletteIndexSelected(QModelIndex))); connect(m_ui->paletteView, SIGNAL(clicked(QModelIndex)), SLOT(slotPaletteIndexClicked(QModelIndex))); connect(m_ui->paletteView, SIGNAL(doubleClicked(QModelIndex)), SLOT(slotPaletteIndexDoubleClicked(QModelIndex))); m_viewContextMenu.addAction(m_actModify.data()); m_viewContextMenu.addAction(m_actRemove.data()); connect(m_ui->paletteView, SIGNAL(pressed(QModelIndex)), SLOT(slotContextMenu(QModelIndex))); m_paletteChooser->setAllowModification(true); connect(m_paletteChooser, SIGNAL(sigPaletteSelected(KoColorSet*)), SLOT(slotSetColorSet(KoColorSet*))); connect(m_paletteChooser, SIGNAL(sigAddPalette()), SLOT(slotAddPalette())); connect(m_paletteChooser, SIGNAL(sigImportPalette()), SLOT(slotImportPalette())); connect(m_paletteChooser, SIGNAL(sigRemovePalette(KoColorSet*)), SLOT(slotRemovePalette(KoColorSet*))); connect(m_paletteChooser, SIGNAL(sigExportPalette(KoColorSet*)), SLOT(slotExportPalette(KoColorSet*))); m_ui->bnColorSets->setIcon(KisIconUtils::loadIcon("hi16-palette_library")); m_ui->bnColorSets->setToolTip(i18n("Choose palette")); m_ui->bnColorSets->setPopupWidget(m_paletteChooser); KisConfig cfg(true); QString defaultPaletteName = cfg.defaultPalette(); - KoColorSet* defaultPalette = m_rServer->resourceByName(defaultPaletteName); + KoColorSetSP defaultPalette = m_rServer->resourceByName(defaultPaletteName); if (defaultPalette) { slotSetColorSet(defaultPalette); } else { m_ui->bnAdd->setEnabled(false); m_ui->bnRename->setEnabled(false); m_ui->bnRemove->setEnabled(false); m_ui->bnEditPalette->setEnabled(false); m_ui->paletteView->setAllowModification(false); } } PaletteDockerDock::~PaletteDockerDock() { } void PaletteDockerDock::setViewManager(KisViewManager* kisview) { m_view = kisview; m_resourceProvider = kisview->resourceProvider(); connect(m_resourceProvider, SIGNAL(sigSavingWorkspace(KisWorkspaceResource*)), SLOT(saveToWorkspace(KisWorkspaceResource*))); connect(m_resourceProvider, SIGNAL(sigLoadingWorkspace(KisWorkspaceResource*)), SLOT(loadFromWorkspace(KisWorkspaceResource*))); connect(m_resourceProvider, SIGNAL(sigFGColorChanged(KoColor)), m_ui->paletteView, SLOT(slotFGColorChanged(KoColor))); kisview->nodeManager()->disconnect(m_model); } void PaletteDockerDock::slotContextMenu(const QModelIndex &) { if (QApplication::mouseButtons() == Qt::RightButton) { m_viewContextMenu.exec(QCursor::pos()); } } void PaletteDockerDock::slotAddPalette() { m_paletteEditor->addPalette(); } -void PaletteDockerDock::slotRemovePalette(KoColorSet *cs) +void PaletteDockerDock::slotRemovePalette(KoColorSetSP cs) { m_paletteEditor->removePalette(cs); } void PaletteDockerDock::slotImportPalette() { m_paletteEditor->importPalette(); } -void PaletteDockerDock::slotExportPalette(KoColorSet *palette) +void PaletteDockerDock::slotExportPalette(KoColorSetSP palette) { KoFileDialog dialog(this, KoFileDialog::SaveFile, "Save Palette"); dialog.setDefaultDir(palette->filename()); dialog.setMimeTypeFilters(QStringList() << "krita/x-colorset"); QString newPath; bool isStandAlone = palette->isGlobal(); QString oriPath = palette->filename(); if ((newPath = dialog.filename()).isEmpty()) { return; } palette->setFilename(newPath); palette->setIsGlobal(true); palette->save(); palette->setFilename(oriPath); palette->setIsGlobal(isStandAlone); } void PaletteDockerDock::setCanvas(KoCanvasBase *canvas) { setEnabled(canvas != Q_NULLPTR); if (canvas) { KisCanvas2 *cv = qobject_cast(canvas); m_ui->paletteView->setDisplayRenderer(cv->displayColorConverter()->displayRendererInterface()); } if (m_activeDocument) { - for (KoColorSet * &cs : m_activeDocument->paletteList()) { - KoColorSet *tmpAddr = cs; - cs = new KoColorSet(*cs); + for (KoColorSetSP &cs : m_activeDocument->paletteList()) { + KoColorSetSP tmpAddr = cs; + cs = KoColorSetSP(new KoColorSet(*cs)); m_rServer->removeResourceFromServer(tmpAddr); } } if (m_view && m_view->document()) { m_activeDocument = m_view->document(); m_paletteEditor->setView(m_view); - for (KoColorSet *cs : m_activeDocument->paletteList()) { + for (KoColorSetSP cs : m_activeDocument->paletteList()) { m_rServer->addResource(cs); } } if (!m_currentColorSet) { slotSetColorSet(Q_NULLPTR); } } void PaletteDockerDock::unsetCanvas() { setEnabled(false); m_ui->paletteView->setDisplayRenderer(Q_NULLPTR); m_paletteEditor->setView(Q_NULLPTR); - for (KoResource *r : m_rServer->resources()) { - KoColorSet *c = static_cast(r); + for (KoResourceSP r : m_rServer->resources()) { + KoColorSetSP c = r.staticCast(); if (!c->isGlobal()) { m_rServer->removeResourceFromServer(c); } } if (!m_currentColorSet) { slotSetColorSet(Q_NULLPTR); } } -void PaletteDockerDock::slotSetColorSet(KoColorSet* colorSet) +void PaletteDockerDock::slotSetColorSet(KoColorSetSP colorSet) { if (colorSet && colorSet->isEditable()) { m_ui->bnAdd->setEnabled(true); m_ui->bnRename->setEnabled(true); m_ui->bnRemove->setEnabled(true); m_ui->bnEditPalette->setEnabled(true); m_ui->paletteView->setAllowModification(true); } else { m_ui->bnAdd->setEnabled(false); m_ui->bnRename->setEnabled(false); m_ui->bnRemove->setEnabled(false); m_ui->bnEditPalette->setEnabled(false); m_ui->paletteView->setAllowModification(false); } m_currentColorSet = colorSet; m_model->setPalette(colorSet); if (colorSet) { KisConfig cfg(true); cfg.setDefaultPalette(colorSet->name()); m_ui->lblPaletteName->setTextElideMode(Qt::ElideLeft); m_ui->lblPaletteName->setText(colorSet->name()); } else { m_ui->lblPaletteName->setText(""); } } void PaletteDockerDock::slotEditPalette() { KisDlgPaletteEditor dlg; if (!m_currentColorSet) { return; } dlg.setPaletteModel(m_model); dlg.setView(m_view); if (dlg.exec() != QDialog::Accepted){ return; } slotSetColorSet(m_currentColorSet); // update GUI } void PaletteDockerDock::slotAddColor() { if (m_resourceProvider) { m_paletteEditor->addEntry(m_resourceProvider->fgColor()); } } void PaletteDockerDock::slotRemoveColor() { QModelIndex index = m_ui->paletteView->currentIndex(); if (!index.isValid()) { return; } m_paletteEditor->removeEntry(index); m_ui->bnRemove->setEnabled(false); } void PaletteDockerDock::setFGColorByPalette(const KisSwatch &entry) { if (m_resourceProvider) { m_resourceProvider->setFGColor(entry.color()); } } void PaletteDockerDock::saveToWorkspace(KisWorkspaceResource* workspace) { if (!m_currentColorSet.isNull()) { workspace->setProperty("palette", m_currentColorSet->name()); } } void PaletteDockerDock::loadFromWorkspace(KisWorkspaceResource* workspace) { if (workspace->hasProperty("palette")) { KoResourceServer* rServer = KoResourceServerProvider::instance()->paletteServer(); - KoColorSet* colorSet = rServer->resourceByName(workspace->getString("palette")); + KoColorSetSP colorSet = rServer->resourceByName(workspace->getString("palette")); if (colorSet) { slotSetColorSet(colorSet); } } } void PaletteDockerDock::slotPaletteIndexSelected(const QModelIndex &index) { bool occupied = qvariant_cast(index.data(KisPaletteModel::CheckSlotRole)); if (occupied) { if (!qvariant_cast(index.data(KisPaletteModel::IsGroupNameRole))) { m_ui->bnRemove->setEnabled(true); KisSwatch entry = m_model->getEntry(index); setFGColorByPalette(entry); } } if (!m_currentColorSet->isEditable()) { return; } m_ui->bnRemove->setEnabled(occupied); } void PaletteDockerDock::slotPaletteIndexClicked(const QModelIndex &index) { if (!(qvariant_cast(index.data(KisPaletteModel::CheckSlotRole)))) { setEntryByForeground(index); } } void PaletteDockerDock::slotPaletteIndexDoubleClicked(const QModelIndex &index) { m_paletteEditor->modifyEntry(index); } void PaletteDockerDock::setEntryByForeground(const QModelIndex &index) { m_paletteEditor->setEntry(m_resourceProvider->fgColor(), index); if (m_currentColorSet->isEditable()) { m_ui->bnRemove->setEnabled(true); } } void PaletteDockerDock::slotEditEntry() { QModelIndex index = m_ui->paletteView->currentIndex(); if (!index.isValid()) { return; } m_paletteEditor->modifyEntry(index); } void PaletteDockerDock::slotNameListSelection(const KoColor &color) { m_resourceProvider->setFGColor(color); } diff --git a/plugins/dockers/palettedocker/palettedocker_dock.h b/plugins/dockers/palettedocker/palettedocker_dock.h index c56fe112c4..9e79ac8b5a 100644 --- a/plugins/dockers/palettedocker/palettedocker_dock.h +++ b/plugins/dockers/palettedocker/palettedocker_dock.h @@ -1,111 +1,111 @@ /* * Copyright (c) 2013 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 PALETTEDOCKER_DOCK_H #define PALETTEDOCKER_DOCK_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include class KisViewManager; class KisCanvasResourceProvider; class KisWorkspaceResource; class KisPaletteListWidget; class KisPaletteModel; class KisPaletteEditor; class Ui_WdgPaletteDock; class PaletteDockerDock : public QDockWidget, public KisMainwindowObserver { Q_OBJECT public: PaletteDockerDock(); ~PaletteDockerDock() override; public: // QDockWidget void setCanvas(KoCanvasBase *canvas) override; void unsetCanvas() override; public: // KisMainWindowObserver void setViewManager(KisViewManager* kisview) override; private Q_SLOTS: void slotContextMenu(const QModelIndex &); void slotAddPalette(); - void slotRemovePalette(KoColorSet *); + void slotRemovePalette(KoColorSetSP ); void slotImportPalette(); - void slotExportPalette(KoColorSet *); + void slotExportPalette(KoColorSetSP ); void slotAddColor(); void slotRemoveColor(); void slotEditEntry(); void slotEditPalette(); void slotPaletteIndexSelected(const QModelIndex &index); void slotPaletteIndexClicked(const QModelIndex &index); void slotPaletteIndexDoubleClicked(const QModelIndex &index); void slotNameListSelection(const KoColor &color); - void slotSetColorSet(KoColorSet* colorSet); + void slotSetColorSet(KoColorSetSP colorSet); void saveToWorkspace(KisWorkspaceResource* workspace); void loadFromWorkspace(KisWorkspaceResource* workspace); private: void setEntryByForeground(const QModelIndex &index); void setFGColorByPalette(const KisSwatch &entry); private /* member variables */: QScopedPointer m_ui; KisPaletteModel *m_model; KisPaletteListWidget *m_paletteChooser; QPointer m_view; KisCanvasResourceProvider *m_resourceProvider; KoResourceServer * const m_rServer; QPointer m_activeDocument; - QPointer m_currentColorSet; + QSharedPointer m_currentColorSet; QScopedPointer m_paletteEditor; QScopedPointer m_actAdd; QScopedPointer m_actRemove; QScopedPointer m_actModify; QScopedPointer m_actEditPalette; QMenu m_viewContextMenu; }; #endif diff --git a/plugins/dockers/patterndocker/patterndocker_dock.cpp b/plugins/dockers/patterndocker/patterndocker_dock.cpp index 72d6d43bbc..9523143903 100644 --- a/plugins/dockers/patterndocker/patterndocker_dock.cpp +++ b/plugins/dockers/patterndocker/patterndocker_dock.cpp @@ -1,69 +1,69 @@ /* * Copyright (c) 2009 Cyrille Berger * * 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; version 2.1 of the License. * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "patterndocker_dock.h" #include #include #include #include #include #include #include PatternDockerDock::PatternDockerDock( ) : QDockWidget(i18n("Patterns")) { m_patternChooser = new KisPatternChooser(this); m_patternChooser->setPreviewOrientation(Qt::Vertical); m_patternChooser->setCurrentItem(0,0); m_patternChooser->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); m_patternChooser->setMinimumHeight(160); setWidget(m_patternChooser); } void PatternDockerDock::setViewManager(KisViewManager* kisview) { KisCanvasResourceProvider* resourceProvider = kisview->resourceProvider(); - connect(resourceProvider, SIGNAL(sigPatternChanged(KoPattern*)), - this, SLOT(patternChanged(KoPattern*))); + connect(resourceProvider, SIGNAL(sigPatternChanged(KoPatternSP)), + this, SLOT(patternChanged(KoPatternSP))); - connect(m_patternChooser, SIGNAL(resourceSelected(KoResource*)), - resourceProvider, SLOT(slotPatternActivated(KoResource*))); + connect(m_patternChooser, SIGNAL(resourceSelected(KoResourceSP )), + resourceProvider, SLOT(slotPatternActivated(KoResourceSP ))); } void PatternDockerDock::setCanvas(KoCanvasBase *canvas) { setEnabled(canvas != 0); } void PatternDockerDock::unsetCanvas() { setEnabled(false); } -void PatternDockerDock::patternChanged(KoPattern *pattern) +void PatternDockerDock::patternChanged(KoPatternSP pattern) { m_patternChooser->setCurrentPattern(pattern); } diff --git a/plugins/dockers/patterndocker/patterndocker_dock.h b/plugins/dockers/patterndocker/patterndocker_dock.h index bc4113b6c5..ad58706ec6 100644 --- a/plugins/dockers/patterndocker/patterndocker_dock.h +++ b/plugins/dockers/patterndocker/patterndocker_dock.h @@ -1,46 +1,47 @@ /* * Copyright (c) 2009 Cyrille Berger * * 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; version 2.1 of the License. * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _PATTERN_DOCK_H_ #define _PATTERN_DOCK_H_ #include #include -class KoPattern; +#include + class KisPatternChooser; class PatternDockerDock : public QDockWidget, public KisMainwindowObserver { Q_OBJECT public: PatternDockerDock( ); void setViewManager(KisViewManager* kisview) override; void setCanvas(KoCanvasBase *canvas) override; void unsetCanvas() override; QString observerName() override { return "PatternDockerDock"; } public Q_SLOTS: - void patternChanged(KoPattern *pattern); + void patternChanged(KoPatternSP pattern); private Q_SLOTS: private: KisPatternChooser* m_patternChooser; }; #endif diff --git a/plugins/dockers/presetdocker/presetdocker_dock.cpp b/plugins/dockers/presetdocker/presetdocker_dock.cpp index 9ee9c152d2..edaba9291d 100644 --- a/plugins/dockers/presetdocker/presetdocker_dock.cpp +++ b/plugins/dockers/presetdocker/presetdocker_dock.cpp @@ -1,85 +1,85 @@ /* * Copyright (c) 2009 Cyrille Berger * * 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; version 2.1 of the License. * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "presetdocker_dock.h" #include #include #include #include #include #include "kis_canvas2.h" #include "KisViewManager.h" #include "kis_paintop_box.h" #include "kis_paintop_presets_chooser_popup.h" #include "kis_canvas_resource_provider.h" #include PresetDockerDock::PresetDockerDock( ) : QDockWidget(i18n("Brush Presets")) , m_canvas(0) { m_presetChooser = new KisPaintOpPresetsChooserPopup(this); m_presetChooser->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); m_presetChooser->showButtons(false); setWidget(m_presetChooser); } void PresetDockerDock::setCanvas(KoCanvasBase *canvas) { setEnabled(canvas != 0); if (m_canvas) { m_canvas->disconnectCanvasObserver(this); m_presetChooser->disconnect(m_canvas->viewManager()->paintOpBox()); } m_canvas = dynamic_cast(canvas); if (!m_canvas || !m_canvas->viewManager() || !m_canvas->resourceManager()) return; - connect(m_presetChooser, SIGNAL(resourceSelected(KoResource*)), - m_canvas->viewManager()->paintOpBox(), SLOT(resourceSelected(KoResource*))); - connect(m_presetChooser, SIGNAL(resourceClicked(KoResource*)), - m_canvas->viewManager()->paintOpBox(), SLOT(resourceSelected(KoResource*))); + connect(m_presetChooser, SIGNAL(resourceSelected(KoResourceSP )), + m_canvas->viewManager()->paintOpBox(), SLOT(resourceSelected(KoResourceSP ))); + connect(m_presetChooser, SIGNAL(resourceClicked(KoResourceSP )), + m_canvas->viewManager()->paintOpBox(), SLOT(resourceSelected(KoResourceSP ))); connect(canvas->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)), this, SLOT(canvasResourceChanged(int,QVariant))); connect(m_canvas->viewManager()->mainWindow(), SIGNAL(themeChanged()), m_presetChooser, SLOT(slotThemeChanged())); canvasResourceChanged(); } void PresetDockerDock::canvasResourceChanged(int /*key*/, const QVariant& /*v*/) { if (m_canvas && m_canvas->resourceManager()) { if (sender()) sender()->blockSignals(true); KisPaintOpPresetSP preset = m_canvas->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value(); if(preset) m_presetChooser->canvasResourceChanged(preset); if (sender()) sender()->blockSignals(false); m_presetChooser->updateViewSettings(); } } diff --git a/plugins/dockers/presethistory/presethistory_dock.cpp b/plugins/dockers/presethistory/presethistory_dock.cpp index cb7023c848..bead0764ae 100644 --- a/plugins/dockers/presethistory/presethistory_dock.cpp +++ b/plugins/dockers/presethistory/presethistory_dock.cpp @@ -1,150 +1,150 @@ /* * Copyright (c) 2015 Boudewijn Rempt * * 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; version 2.1 of the License. * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "presethistory_dock.h" #include #include #include #include #include #include #include #include "kis_config.h" #include "kis_canvas2.h" #include "KisViewManager.h" #include "kis_paintop_box.h" #include "kis_paintop_presets_chooser_popup.h" #include "kis_canvas_resource_provider.h" #include "KisResourceServerProvider.h" #include #include #include #define ICON_SIZE 48 PresetHistoryDock::PresetHistoryDock( ) : QDockWidget(i18n("Brush Preset History")) , m_canvas(0) , m_block(false) , m_initialized(false) { m_presetHistory = new QListWidget(this); m_presetHistory->setIconSize(QSize(ICON_SIZE, ICON_SIZE)); m_presetHistory->setDragEnabled(false); m_presetHistory->setSelectionBehavior(QAbstractItemView::SelectRows); m_presetHistory->setSelectionMode(QAbstractItemView::SingleSelection); m_presetHistory->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); setWidget(m_presetHistory); QScroller* scroller = KisKineticScroller::createPreconfiguredScroller(m_presetHistory); if( scroller ) { connect(scroller, SIGNAL(stateChanged(QScroller::State)), this, SLOT(slotScrollerStateChanged(QScroller::State))); } connect(m_presetHistory, SIGNAL(itemClicked(QListWidgetItem*)), SLOT(presetSelected(QListWidgetItem*))); } void PresetHistoryDock::setCanvas(KoCanvasBase * canvas) { setEnabled(canvas != 0); if (m_canvas) { m_canvas->disconnectCanvasObserver(this); disconnect(m_canvas->resourceManager()); } m_canvas = dynamic_cast(canvas); if (!m_canvas || !m_canvas->viewManager() || !m_canvas->resourceManager()) return; connect(canvas->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)), SLOT(canvasResourceChanged(int,QVariant))); if (!m_initialized) { KisConfig cfg(true); QStringList presetHistory = cfg.readEntry("presethistory", "").split(",", QString::SkipEmptyParts); KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); Q_FOREACH (const QString &p, presetHistory) { KisPaintOpPresetSP preset = rserver->resourceByName(p); addPreset(preset); } m_initialized = true; } } void PresetHistoryDock::unsetCanvas() { m_canvas = 0; setEnabled(false); QStringList presetHistory; for(int i = m_presetHistory->count() -1; i >=0; --i) { QListWidgetItem *item = m_presetHistory->item(i); QVariant v = item->data(Qt::UserRole); KisPaintOpPresetSP preset = v.value(); presetHistory << preset->name(); } KisConfig cfg(false); cfg.writeEntry("presethistory", presetHistory.join(",")); } void PresetHistoryDock::presetSelected(QListWidgetItem *item) { if (item) { QVariant v = item->data(Qt::UserRole); KisPaintOpPresetSP preset = v.value(); m_block = true; - m_canvas->viewManager()->paintOpBox()->resourceSelected(preset.data()); + m_canvas->viewManager()->paintOpBox()->resourceSelected(preset); m_block = false; } } void PresetHistoryDock::canvasResourceChanged(int key, const QVariant& /*v*/) { if (m_block) return; if (m_canvas && key == KisCanvasResourceProvider::CurrentPaintOpPreset) { KisPaintOpPresetSP preset = m_canvas->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value(); if (preset) { for (int i = 0; i < m_presetHistory->count(); ++i) { if (preset->name() == m_presetHistory->item(i)->text()) { m_presetHistory->setCurrentRow(i); return; } } addPreset(preset); } } } void PresetHistoryDock::addPreset(KisPaintOpPresetSP preset) { if (preset) { QListWidgetItem *item = new QListWidgetItem(QPixmap::fromImage(preset->image()), preset->name()); QVariant v = QVariant::fromValue(preset); item->setData(Qt::UserRole, v); m_presetHistory->insertItem(0, item); m_presetHistory->setCurrentRow(0); if (m_presetHistory->count() > 10) { m_presetHistory->takeItem(10); } } } diff --git a/plugins/dockers/svgcollectiondocker/SvgSymbolCollectionDocker.cpp b/plugins/dockers/svgcollectiondocker/SvgSymbolCollectionDocker.cpp index 9c9a9ffd74..e51e2baa9f 100644 --- a/plugins/dockers/svgcollectiondocker/SvgSymbolCollectionDocker.cpp +++ b/plugins/dockers/svgcollectiondocker/SvgSymbolCollectionDocker.cpp @@ -1,254 +1,254 @@ /* This file is part of the KDE project * Copyright (C) 2008 Peter Simonsson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "SvgSymbolCollectionDocker.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_icon_utils.h" #include #include #include "ui_WdgSvgCollection.h" #include // // SvgCollectionModel // SvgCollectionModel::SvgCollectionModel(QObject *parent) : QAbstractListModel(parent) { } QVariant SvgCollectionModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() > m_symbolCollection->symbols().count()) { return QVariant(); } switch (role) { case Qt::ToolTipRole: return m_symbolCollection->symbols()[index.row()]->title; case Qt::DecorationRole: { QPixmap px = QPixmap::fromImage(m_symbolCollection->symbols()[index.row()]->icon()); QIcon icon(px); return icon; } case Qt::UserRole: return m_symbolCollection->symbols()[index.row()]->id; case Qt::DisplayRole: return m_symbolCollection->symbols()[index.row()]->title; default: return QVariant(); } return QVariant(); } int SvgCollectionModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return m_symbolCollection->symbols().count(); } QMimeData *SvgCollectionModel::mimeData(const QModelIndexList &indexes) const { if (indexes.isEmpty()) { return 0; } QModelIndex index = indexes.first(); if (!index.isValid()) { return 0; } if (m_symbolCollection->symbols().isEmpty()) { return 0; } QList shapes; shapes.append(m_symbolCollection->symbols()[index.row()]->shape); KoDrag drag; drag.setSvg(shapes); QMimeData *mimeData = drag.mimeData(); return mimeData; } QStringList SvgCollectionModel::mimeTypes() const { return QStringList() << SHAPETEMPLATE_MIMETYPE << "image/svg+xml"; } Qt::ItemFlags SvgCollectionModel::flags(const QModelIndex &index) const { if (index.isValid()) { return QAbstractListModel::flags(index) | Qt::ItemIsDragEnabled; } return QAbstractListModel::flags(index); } Qt::DropActions SvgCollectionModel::supportedDragActions() const { return Qt::CopyAction; } -void SvgCollectionModel::setSvgSymbolCollectionResource(KoSvgSymbolCollectionResource *resource) +void SvgCollectionModel::setSvgSymbolCollectionResource(QSharedPointer resource) { m_symbolCollection = resource; } // // SvgSymbolCollectionDockerFactory // SvgSymbolCollectionDockerFactory::SvgSymbolCollectionDockerFactory() : KoDockFactoryBase() { } QString SvgSymbolCollectionDockerFactory::id() const { return QString("SvgSymbolCollectionDocker"); } QDockWidget *SvgSymbolCollectionDockerFactory::createDockWidget() { SvgSymbolCollectionDocker *docker = new SvgSymbolCollectionDocker(); return docker; } // // SvgSymbolCollectionDocker // SvgSymbolCollectionDocker::SvgSymbolCollectionDocker(QWidget *parent) : QDockWidget(parent) , m_wdgSvgCollection(new Ui_WdgSvgCollection()) { setWindowTitle(i18n("Vector Libraries")); QWidget* mainWidget = new QWidget(this); setWidget(mainWidget); m_wdgSvgCollection->setupUi(mainWidget); connect(m_wdgSvgCollection->cmbCollections, SIGNAL(activated(int)), SLOT(collectionActivated(int))); KoResourceServer *svgCollectionProvider = KoResourceServerProvider::instance()->svgSymbolCollectionServer(); - Q_FOREACH(KoSvgSymbolCollectionResource *r, svgCollectionProvider->resources()) { + Q_FOREACH(QSharedPointer r, svgCollectionProvider->resources()) { m_wdgSvgCollection->cmbCollections->addSqueezedItem(r->name()); SvgCollectionModel *model = new SvgCollectionModel(); model->setSvgSymbolCollectionResource(r); m_models.append(model); } m_wdgSvgCollection->listCollection->setDragEnabled(true); m_wdgSvgCollection->listCollection->setDragDropMode(QAbstractItemView::DragOnly); m_wdgSvgCollection->listCollection->setSelectionMode(QListView::SingleSelection); QScroller *scroller = KisKineticScroller::createPreconfiguredScroller(m_wdgSvgCollection->listCollection); if (scroller) { connect(scroller, SIGNAL(stateChanged(QScroller::State)), this, SLOT(slotScrollerStateChanged(QScroller::State))); } // thumbnail icon changer QMenu* configureMenu = new QMenu(this); configureMenu->setStyleSheet("margin: 6px"); m_wdgSvgCollection->vectorPresetsConfigureButton->setIcon(KisIconUtils::loadIcon("configure")); m_wdgSvgCollection->vectorPresetsConfigureButton->setPopupMode(QToolButton::InstantPopup); // add horizontal slider for changing the icon size m_iconSizeSlider = new QSlider(this); m_iconSizeSlider->setOrientation(Qt::Horizontal); m_iconSizeSlider->setRange(20, 80); m_iconSizeSlider->setValue(20); // defaults to small icon size m_iconSizeSlider->setMinimumHeight(20); m_iconSizeSlider->setMinimumWidth(40); m_iconSizeSlider->setTickInterval(10); QWidgetAction *sliderAction= new QWidgetAction(this); sliderAction->setDefaultWidget(m_iconSizeSlider); configureMenu->addSection(i18n("Icon Size")); configureMenu->addAction(sliderAction); m_wdgSvgCollection->vectorPresetsConfigureButton->setMenu(configureMenu); connect(m_iconSizeSlider, SIGNAL(sliderReleased()), this, SLOT(slotSetIconSize())); // resizing while sliding is too heavy of an operation KConfigGroup cfg = KSharedConfig::openConfig()->group("SvgSymbolCollection"); int i = cfg.readEntry("currentCollection", 0); if (i > m_wdgSvgCollection->cmbCollections->count()) { i = 0; } m_wdgSvgCollection->cmbCollections->setCurrentIndex(i); collectionActivated(i); } void SvgSymbolCollectionDocker::slotSetIconSize() { m_wdgSvgCollection->listCollection->setIconSize(QSize(m_iconSizeSlider->value(),m_iconSizeSlider->value())); } void SvgSymbolCollectionDocker::setCanvas(KoCanvasBase *canvas) { setEnabled(canvas != 0); } void SvgSymbolCollectionDocker::unsetCanvas() { setEnabled(false); } void SvgSymbolCollectionDocker::collectionActivated(int index) { if (index < m_models.size()) { KConfigGroup cfg = KSharedConfig::openConfig()->group("SvgSymbolCollection"); cfg.writeEntry("currentCollection", index); m_wdgSvgCollection->listCollection->setModel(m_models[index]); } } diff --git a/plugins/dockers/svgcollectiondocker/SvgSymbolCollectionDocker.h b/plugins/dockers/svgcollectiondocker/SvgSymbolCollectionDocker.h index 00171e0a4d..53fe6cf380 100644 --- a/plugins/dockers/svgcollectiondocker/SvgSymbolCollectionDocker.h +++ b/plugins/dockers/svgcollectiondocker/SvgSymbolCollectionDocker.h @@ -1,92 +1,92 @@ /* This file is part of the KDE project * Copyright (C) 2017 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef SVGSYMBOLCOLLECTIONDOCKER_H #define SVGSYMBOLCOLLECTIONDOCKER_H #include #include #include #include #include #include #include #include #include "ui_WdgSvgCollection.h" class KoSvgSymbolCollectionResource; class SvgCollectionModel : public QAbstractListModel { Q_OBJECT public: explicit SvgCollectionModel(QObject *parent = 0); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; QMimeData *mimeData(const QModelIndexList &indexes) const override; QStringList mimeTypes() const override; Qt::ItemFlags flags(const QModelIndex &index) const override; Qt::DropActions supportedDragActions() const override; public: - void setSvgSymbolCollectionResource(KoSvgSymbolCollectionResource *resource); + void setSvgSymbolCollectionResource(QSharedPointer resource); private: - KoSvgSymbolCollectionResource *m_symbolCollection; + QSharedPointer m_symbolCollection; }; class SvgSymbolCollectionDockerFactory : public KoDockFactoryBase { public: SvgSymbolCollectionDockerFactory(); QString id() const override; QDockWidget *createDockWidget() override; DockPosition defaultDockPosition() const override { return DockRight; } }; class SvgSymbolCollectionDocker : public QDockWidget, public KoCanvasObserverBase { Q_OBJECT public: explicit SvgSymbolCollectionDocker(QWidget *parent = 0); /// reimplemented void setCanvas(KoCanvasBase *canvas) override; void unsetCanvas() override; public Q_SLOTS: void slotScrollerStateChanged(QScroller::State state){KisKineticScroller::updateCursor(this, state);} private Q_SLOTS: void collectionActivated(int index); void slotSetIconSize(); private: Ui_WdgSvgCollection *m_wdgSvgCollection; QVector m_models; QSlider* m_iconSizeSlider; }; #endif //KOSHAPECOLLECTIONDOCKER_H diff --git a/plugins/dockers/tasksetdocker/taskset_resource.h b/plugins/dockers/tasksetdocker/taskset_resource.h index 4f2f56e75b..4018047dd8 100644 --- a/plugins/dockers/tasksetdocker/taskset_resource.h +++ b/plugins/dockers/tasksetdocker/taskset_resource.h @@ -1,48 +1,50 @@ /* * Copyright (c) 2011 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; version 2.1 of the License. * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef TASKSET_RESOURCE_H #define TASKSET_RESOURCE_H #include #include class TasksetResource : public KoResource { public: TasksetResource(const QString& filename); ~TasksetResource() override; bool load() override; bool loadFromDevice(QIODevice *dev) override; bool save() override; bool saveToDevice(QIODevice* dev) const override; QString defaultFileExtension() const override; void setActionList(const QStringList actions); QStringList actionList(); private: QStringList m_actions; }; +typedef QSharedPointer TasksetResourceSP; + #endif // TASKSET_RESOURCE_H diff --git a/plugins/dockers/tasksetdocker/tasksetdocker_dock.cpp b/plugins/dockers/tasksetdocker/tasksetdocker_dock.cpp index 4fa9546755..bfa191128f 100644 --- a/plugins/dockers/tasksetdocker/tasksetdocker_dock.cpp +++ b/plugins/dockers/tasksetdocker/tasksetdocker_dock.cpp @@ -1,244 +1,244 @@ /* * Copyright (c) 2011 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; version 2.1 of the License. * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "tasksetdocker_dock.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tasksetmodel.h" class KisTasksetDelegate : public QStyledItemDelegate { public: KisTasksetDelegate(QObject * parent = 0) : QStyledItemDelegate(parent) {} ~KisTasksetDelegate() override {} /// reimplemented QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const override { return QSize(QStyledItemDelegate::sizeHint(option, index).width(), qMin(QStyledItemDelegate::sizeHint(option, index).width(), 25)); } }; class KisTasksetResourceDelegate : public QStyledItemDelegate { public: KisTasksetResourceDelegate(QObject * parent = 0) : QStyledItemDelegate(parent) {} ~KisTasksetResourceDelegate() override {} /// reimplemented void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override; }; void KisTasksetResourceDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { if (! index.isValid()) return; TasksetResource* taskset = static_cast(index.internalPointer()); if (option.state & QStyle::State_Selected) { painter->setPen(QPen(option.palette.highlight(), 2.0)); painter->fillRect(option.rect, option.palette.highlight()); painter->setBrush(option.palette.highlightedText()); } else { painter->setBrush(option.palette.text()); } painter->drawText(option.rect.x() + 5, option.rect.y() + painter->fontMetrics().ascent() + 5, taskset->name()); } TasksetDockerDock::TasksetDockerDock( ) : QDockWidget(i18n("Task Sets")), m_canvas(0), m_blocked(false) { QWidget* widget = new QWidget(this); setupUi(widget); m_model = new TasksetModel(this); tasksetView->setModel(m_model); tasksetView->setItemDelegate(new KisTasksetDelegate(this)); recordButton->setIcon(KisIconUtils::loadIcon("media-record")); recordButton->setCheckable(true); clearButton->setIcon(KisIconUtils::loadIcon("edit-delete")); saveButton->setIcon(KisIconUtils::loadIcon("document-save")); saveButton->setEnabled(false); chooserButton->setIcon(KisIconUtils::loadIcon("edit-copy")); KisResourceLoaderRegistry::instance()->add(new KisResourceLoader("taskset", "taskset", QStringList() << "application/x-krita-taskset")); m_rserver = new KoResourceServerSimpleConstruction("kis_taskset", "*.kts"); if (!QFileInfo(m_rserver->saveLocation()).exists()) { QDir().mkpath(m_rserver->saveLocation()); } QSharedPointer adapter (new KoResourceServerAdapter(m_rserver)); m_rserver->loadResources(KoResourceServerProvider::blacklistFileNames(m_rserver->fileNames(), m_rserver->blackListedFiles())); m_rserver->loadTags(); KoResourceItemChooser* itemChooser = new KoResourceItemChooser(adapter, this); itemChooser->setItemDelegate(new KisTasksetResourceDelegate(this)); itemChooser->setFixedSize(500, 250); itemChooser->setRowHeight(30); itemChooser->setColumnCount(1); itemChooser->showTaggingBar(true); chooserButton->setPopupWidget(itemChooser); - connect(itemChooser, SIGNAL(resourceSelected(KoResource*)), this, SLOT(resourceSelected(KoResource*))); + connect(itemChooser, SIGNAL(resourceSelected(KoResourceSP )), this, SLOT(resourceSelected(KoResourceSP ))); setWidget(widget); connect( tasksetView, SIGNAL(clicked(QModelIndex)), this, SLOT(activated(QModelIndex)) ); connect( recordButton, SIGNAL(toggled(bool)), this, SLOT(recordClicked())); connect( clearButton, SIGNAL(clicked(bool)), this, SLOT(clearClicked())); connect( saveButton, SIGNAL(clicked(bool)), this, SLOT(saveClicked())); } TasksetDockerDock::~TasksetDockerDock() { delete m_rserver; } void TasksetDockerDock::setCanvas(KoCanvasBase * canvas) { if (m_canvas && m_canvas->viewManager()) { m_canvas->viewManager()->actionCollection()->disconnect(this); Q_FOREACH (KXMLGUIClient* client, m_canvas->viewManager()->mainWindow()->childClients()) { client->actionCollection()->disconnect(this); } } m_canvas = dynamic_cast(canvas); } void TasksetDockerDock::unsetCanvas() { m_canvas = 0; m_model->clear(); } void TasksetDockerDock::actionTriggered(QAction* action) { if(action && !action->objectName().isEmpty() && !m_blocked && recordButton->isChecked()) { m_model->addAction(action); saveButton->setEnabled(true); } } void TasksetDockerDock::activated(const QModelIndex& index) { QAction* action = m_model->actionFromIndex(index); m_blocked = true; action->trigger(); m_blocked = false; } void TasksetDockerDock::recordClicked() { if(m_canvas) { KisViewManager* view = m_canvas->viewManager(); connect(view->actionCollection(), SIGNAL(actionTriggered(QAction*)), this, SLOT(actionTriggered(QAction*)), Qt::UniqueConnection); Q_FOREACH (KXMLGUIClient* client, view->mainWindow()->childClients()) { connect(client->actionCollection(), SIGNAL(actionTriggered(QAction*)), this, SLOT(actionTriggered(QAction*)), Qt::UniqueConnection); } } } void TasksetDockerDock::saveClicked() { bool ok; QString name = QInputDialog::getText(this, i18n("Taskset Name"), i18n("Name:"), QLineEdit::Normal, QString(), &ok); if (!ok) { return; } - TasksetResource* taskset = new TasksetResource(QString()); + TasksetResourceSP taskset(new TasksetResource(QString())); QStringList actionNames; Q_FOREACH (QAction* action, m_model->actions()) { actionNames.append(action->objectName()); } taskset->setActionList(actionNames); taskset->setValid(true); QString saveLocation = m_rserver->saveLocation(); bool newName = false; if(name.isEmpty()) { newName = true; name = i18n("Taskset"); } QFileInfo fileInfo(saveLocation + name + taskset->defaultFileExtension()); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(saveLocation + name + QString("%1").arg(i) + taskset->defaultFileExtension()); i++; } taskset->setFilename(fileInfo.filePath()); if(newName) { name = i18n("Taskset %1", i); } taskset->setName(name); m_rserver->addResource(taskset); } void TasksetDockerDock::clearClicked() { saveButton->setEnabled(false); m_model->clear(); } -void TasksetDockerDock::resourceSelected(KoResource* resource) +void TasksetDockerDock::resourceSelected(KoResourceSP resource) { if(!m_canvas) { return; } m_model->clear(); saveButton->setEnabled(true); - Q_FOREACH (const QString& actionName, static_cast(resource)->actionList()) { + Q_FOREACH (const QString& actionName, resource.staticCast()->actionList()) { QAction* action = m_canvas->viewManager()->actionCollection()->action(actionName); if(action) { m_model->addAction(action); } } } diff --git a/plugins/dockers/tasksetdocker/tasksetdocker_dock.h b/plugins/dockers/tasksetdocker/tasksetdocker_dock.h index 68efa9ccf3..9c826cfe71 100644 --- a/plugins/dockers/tasksetdocker/tasksetdocker_dock.h +++ b/plugins/dockers/tasksetdocker/tasksetdocker_dock.h @@ -1,61 +1,61 @@ /* * Copyright (c) 2011 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; version 2.1 of the License. * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef TASKSETDOCKER_DOCK_H #define TASKSETDOCKER_DOCK_H #include #include #include #include #include #include #include "taskset_resource.h" #include "ui_wdgtasksetdocker.h" class TasksetModel; class TasksetDockerDock : public QDockWidget, public KoCanvasObserverBase, public Ui_WdgTasksetDocker { Q_OBJECT public: TasksetDockerDock(); ~TasksetDockerDock() override; QString observerName() override { return "TasksetDockerDock"; } void setCanvas(KoCanvasBase *canvas) override; void unsetCanvas() override; private Q_SLOTS: void actionTriggered(QAction* action); void activated (const QModelIndex& index); void recordClicked(); void saveClicked(); void clearClicked(); - void resourceSelected( KoResource * resource ); + void resourceSelected( KoResourceSP resource ); private: QPointer m_canvas; TasksetModel *m_model; bool m_blocked; KoResourceServer* m_rserver; }; #endif diff --git a/plugins/extensions/layersplit/dlg_layersplit.cpp b/plugins/extensions/layersplit/dlg_layersplit.cpp index bae3035cd9..365ed53ba1 100644 --- a/plugins/extensions/layersplit/dlg_layersplit.cpp +++ b/plugins/extensions/layersplit/dlg_layersplit.cpp @@ -1,148 +1,148 @@ /* * Copyright (C) 2014 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "dlg_layersplit.h" #include #include #include #include #include #include #include "kis_slider_spin_box.h" #include #include #include DlgLayerSplit::DlgLayerSplit() : KoDialog() { m_page = new WdgLayerSplit(this); setCaption(i18n("Split Layer")); setButtons(Apply | Cancel); setDefaultButton(Apply); m_page->intFuzziness->setRange(0, 200); m_page->intFuzziness->setSingleStep(1); m_colorSetChooser = new KisPaletteListWidget(); m_page->paletteChooser->setPopupWidget(m_colorSetChooser); connect(m_colorSetChooser, SIGNAL(sigPaletteSelected(KoColorSet*)), this, SLOT(slotSetPalette(KoColorSet*))); KisConfig cfg(true); m_page->intFuzziness->setValue(cfg.readEntry("layersplit/fuzziness", 20)); m_page->chkCreateGroupLayer->setChecked(cfg.readEntry("layerspit/createmastergroup", true)); m_page->chkSeparateGroupLayers->setChecked(cfg.readEntry("layerspit/separategrouplayers", false)); m_page->chkAlphaLock->setChecked(cfg.readEntry("layerspit/alphalock", true)); m_page->chkHideOriginal->setChecked(cfg.readEntry("layerspit/hideoriginal", false)); m_page->chkSortLayers->setChecked(cfg.readEntry("layerspit/sortlayers", true)); m_page->chkDisregardOpacity->setChecked(cfg.readEntry("layerspit/disregardopacity", true)); QString paletteName = cfg.readEntry("layersplit/paletteName", i18n("Default")); KoResourceServer *pserver = KoResourceServerProvider::instance()->paletteServer(); - KoColorSet *pal = pserver->resourceByName(paletteName); + KoColorSetSP pal = pserver->resourceByName(paletteName); if (pal) { m_palette = pal; m_page->paletteChooser->setText(pal->name()); QIcon icon(QPixmap::fromImage(pal->image())); m_page->paletteChooser->setIcon(icon); } connect(this, SIGNAL(applyClicked()), this, SLOT(applyClicked())); setMainWidget(m_page); } DlgLayerSplit::~DlgLayerSplit() { } void DlgLayerSplit::applyClicked() { KisConfig cfg(false); cfg.writeEntry("layersplit/fuzziness", m_page->intFuzziness->value()); cfg.writeEntry("layerspit/createmastergroup", m_page->chkCreateGroupLayer->isChecked()); cfg.writeEntry("layerspit/separategrouplayers", m_page->chkSeparateGroupLayers->isChecked()); cfg.writeEntry("layerspit/alphalock", m_page->chkAlphaLock->isChecked()); cfg.writeEntry("layerspit/hideoriginal", m_page->chkHideOriginal->isChecked()); cfg.writeEntry("layerspit/sortlayers", m_page->chkSortLayers->isChecked()); cfg.writeEntry("layerspit/disregardopacity", m_page->chkDisregardOpacity->isChecked()); if (m_palette) { cfg.writeEntry("layersplit/paletteName", m_palette->name()); } accept(); } bool DlgLayerSplit::createBaseGroup() const { return m_page->chkCreateGroupLayer->isChecked(); } bool DlgLayerSplit::createSeparateGroups() const { return m_page->chkSeparateGroupLayers->isChecked(); } bool DlgLayerSplit::lockAlpha() const { return m_page->chkAlphaLock->isChecked(); } bool DlgLayerSplit::hideOriginal() const { return m_page->chkHideOriginal->isChecked(); } bool DlgLayerSplit::sortLayers() const { return m_page->chkSortLayers->isChecked(); } bool DlgLayerSplit::disregardOpacity() const { return m_page->chkDisregardOpacity->isChecked(); } int DlgLayerSplit::fuzziness() const { return m_page->intFuzziness->value(); } -KoColorSet *DlgLayerSplit::palette() const +KoColorSetSP DlgLayerSplit::palette() const { return m_palette; } -void DlgLayerSplit::slotSetPalette(KoColorSet *pal) +void DlgLayerSplit::slotSetPalette(KoColorSetSP pal) { if (pal) { m_palette = pal; m_page->paletteChooser->setText(pal->name()); QIcon icon(QPixmap::fromImage(pal->image())); m_page->paletteChooser->setIcon(icon); } } diff --git a/plugins/extensions/layersplit/dlg_layersplit.h b/plugins/extensions/layersplit/dlg_layersplit.h index 4eed5029e1..1edaa30ad8 100644 --- a/plugins/extensions/layersplit/dlg_layersplit.h +++ b/plugins/extensions/layersplit/dlg_layersplit.h @@ -1,63 +1,63 @@ /* * Copyright (C) 2014 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef DLG_LAYERSPLIT #define DLG_LAYERSPLIT #include #include #include #include #include "wdg_layersplit.h" /** * This dialog allows the user to create a selection mask based * on a (range of) colors. */ class DlgLayerSplit: public KoDialog { Q_OBJECT public: DlgLayerSplit(); ~DlgLayerSplit() override; bool createBaseGroup() const; bool createSeparateGroups() const; bool lockAlpha() const; bool hideOriginal() const; bool sortLayers() const; bool disregardOpacity() const; int fuzziness() const; - KoColorSet* palette() const; + KoColorSetSP palette() const; private Q_SLOTS: void applyClicked(); - void slotSetPalette(KoColorSet *pal); + void slotSetPalette(KoColorSetSP pal); private: WdgLayerSplit *m_page {0}; KisPaletteListWidget *m_colorSetChooser {0}; - KoColorSet *m_palette {0}; + KoColorSetSP m_palette {0}; }; #endif // DLG_LAYERSPLIT diff --git a/plugins/extensions/resourcemanager/dlg_bundle_manager.cpp b/plugins/extensions/resourcemanager/dlg_bundle_manager.cpp index 26cd6781a9..04f888cb23 100644 --- a/plugins/extensions/resourcemanager/dlg_bundle_manager.cpp +++ b/plugins/extensions/resourcemanager/dlg_bundle_manager.cpp @@ -1,425 +1,425 @@ /* * Copyright (c) 2014 Victor Lafon metabolic.ewilan@hotmail.fr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "dlg_bundle_manager.h" #include "ui_wdgdlgbundlemanager.h" #include "resourcemanager.h" #include "dlg_create_bundle.h" #include #include #include #include #include #include #include #include "kis_action.h" #include #include #include #define ICON_SIZE 48 DlgBundleManager::DlgBundleManager(ResourceManager *resourceManager, KisActionManager* actionMgr, QWidget *parent) : KoDialog(parent) , m_page(new QWidget()) , m_ui(new Ui::WdgDlgBundleManager) , m_currentBundle(0) , m_resourceManager(resourceManager) { setCaption(i18n("Manage Resource Bundles")); m_ui->setupUi(m_page); setMainWidget(m_page); resize(m_page->sizeHint()); setButtons(Ok | Cancel); setDefaultButton(Ok); m_ui->listActive->setIconSize(QSize(ICON_SIZE, ICON_SIZE)); m_ui->listActive->setSelectionMode(QAbstractItemView::SingleSelection); connect(m_ui->listActive, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), SLOT(itemSelected(QListWidgetItem*,QListWidgetItem*))); connect(m_ui->listActive, SIGNAL(itemClicked(QListWidgetItem*)), SLOT(itemSelected(QListWidgetItem*))); m_ui->listInactive->setIconSize(QSize(ICON_SIZE, ICON_SIZE)); m_ui->listInactive->setSelectionMode(QAbstractItemView::SingleSelection); connect(m_ui->listInactive, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), SLOT(itemSelected(QListWidgetItem*,QListWidgetItem*))); connect(m_ui->listInactive, SIGNAL(itemClicked(QListWidgetItem*)), SLOT(itemSelected(QListWidgetItem*))); m_ui->bnAdd->setIcon(KisIconUtils::loadIcon("arrow-right")); connect(m_ui->bnAdd, SIGNAL(clicked()), SLOT(addSelected())); m_ui->bnRemove->setIcon(KisIconUtils::loadIcon("arrow-left")); connect(m_ui->bnRemove, SIGNAL(clicked()), SLOT(removeSelected())); m_ui->listBundleContents->setHeaderLabel(i18n("Resource")); m_ui->listBundleContents->setSelectionMode(QAbstractItemView::NoSelection); m_actionManager = actionMgr; refreshListData(); connect(m_ui->bnEditBundle, SIGNAL(clicked()), SLOT(editBundle())); connect(m_ui->bnImportBrushes, SIGNAL(clicked()), SLOT(slotImportResource())); connect(m_ui->bnImportGradients, SIGNAL(clicked()), SLOT(slotImportResource())); connect(m_ui->bnImportPalettes, SIGNAL(clicked()), SLOT(slotImportResource())); connect(m_ui->bnImportPatterns, SIGNAL(clicked()), SLOT(slotImportResource())); connect(m_ui->bnImportPresets, SIGNAL(clicked()), SLOT(slotImportResource())); connect(m_ui->bnImportWorkspaces, SIGNAL(clicked()), SLOT(slotImportResource())); connect(m_ui->bnImportBundles, SIGNAL(clicked()), SLOT(slotImportResource())); connect(m_ui->createBundleButton, SIGNAL(clicked()), SLOT(slotCreateBundle())); connect(m_ui->deleteBackupFilesButton, SIGNAL(clicked()), SLOT(slotDeleteBackupFiles())); connect(m_ui->openResourceFolderButton, SIGNAL(clicked()), SLOT(slotOpenResourceFolder())); } void DlgBundleManager::refreshListData() { KoResourceServer *bundleServer = KisResourceBundleServerProvider::instance()->resourceBundleServer(); m_ui->listInactive->clear(); m_ui->listActive->clear(); Q_FOREACH (const QString &f, bundleServer->blackListedFiles()) { - KisResourceBundle *bundle = new KisResourceBundle(f); + KisResourceBundleSP bundle(new KisResourceBundle(f)); bundle->load(); if (bundle->valid()) { bundle->setInstalled(false); m_blacklistedBundles[f] = bundle; } } fillListWidget(m_blacklistedBundles.values(), m_ui->listInactive); - Q_FOREACH (KisResourceBundle *bundle, bundleServer->resources()) { + Q_FOREACH (KisResourceBundleSP bundle, bundleServer->resources()) { if (bundle->valid()) { m_activeBundles[bundle->filename()] = bundle; } } fillListWidget(m_activeBundles.values(), m_ui->listActive); } void DlgBundleManager::accept() { KoResourceServer *bundleServer = KisResourceBundleServerProvider::instance()->resourceBundleServer(); for (int i = 0; i < m_ui->listActive->count(); ++i) { QListWidgetItem *item = m_ui->listActive->item(i); QByteArray ba = item->data(Qt::UserRole).toByteArray(); QString name = item->text(); - KisResourceBundle *bundle = bundleServer->resourceByMD5(ba); + KisResourceBundleSP bundle = bundleServer->resourceByMD5(ba); QMessageBox bundleFeedback; bundleFeedback.setIcon(QMessageBox::Warning); QString feedback = "bundlefeedback"; if (!bundle) { // Get it from the blacklisted bundles - Q_FOREACH (KisResourceBundle *b2, m_blacklistedBundles.values()) { + Q_FOREACH (KisResourceBundleSP b2, m_blacklistedBundles.values()) { if (b2->md5() == ba) { bundle = b2; break; } } } if (bundle) { bool isKrita3Bundle = false; if (bundle->filename().endsWith("Krita_3_Default_Resources.bundle")) { isKrita3Bundle = true; KConfigGroup group = KSharedConfig::openConfig()->group("BundleHack"); group.writeEntry("HideKrita3Bundle", false); } else { if (!bundle->isInstalled()) { bundle->install(); //this removes the bundle from the blacklist and add it to the server without saving or putting it in front// if (!bundleServer->addResource(bundle, false, false)){ feedback = i18n("Couldn't add bundle \"%1\" to resource server", name); bundleFeedback.setText(feedback); bundleFeedback.exec(); } if (!isKrita3Bundle) { if (!bundleServer->removeFromBlacklist(bundle)) { feedback = i18n("Couldn't remove bundle \"%1\" from blacklist", name); bundleFeedback.setText(feedback); bundleFeedback.exec(); } } } else { if (!isKrita3Bundle) { bundleServer->removeFromBlacklist(bundle); } //let's assume that bundles that exist and are installed have to be removed from the blacklist, and if they were already this returns false, so that's not a problem. } } } else{ QString feedback = i18n("Bundle \"%1\" doesn't exist!", name); bundleFeedback.setText(feedback); bundleFeedback.exec(); } } for (int i = 0; i < m_ui->listInactive->count(); ++i) { QListWidgetItem *item = m_ui->listInactive->item(i); QByteArray ba = item->data(Qt::UserRole).toByteArray(); - KisResourceBundle *bundle = bundleServer->resourceByMD5(ba); + KisResourceBundleSP bundle = bundleServer->resourceByMD5(ba); bool isKrits3Bundle = false; if (bundle) { if (bundle->filename().contains("Krita_3_Default_Resources.bundle")) { isKrits3Bundle = true; KConfigGroup group = KSharedConfig::openConfig()->group("BundleHack"); group.writeEntry("HideKrita3Bundle", true); } if (bundle->isInstalled()) { bundle->uninstall(); if (!isKrits3Bundle) { bundleServer->removeResourceAndBlacklist(bundle); } } } } KoDialog::accept(); } void DlgBundleManager::addSelected() { Q_FOREACH (QListWidgetItem *item, m_ui->listActive->selectedItems()) { m_ui->listInactive->addItem(m_ui->listActive->takeItem(m_ui->listActive->row(item))); } } void DlgBundleManager::removeSelected() { Q_FOREACH (QListWidgetItem *item, m_ui->listInactive->selectedItems()) { m_ui->listActive->addItem(m_ui->listInactive->takeItem(m_ui->listInactive->row(item))); } } void DlgBundleManager::itemSelected(QListWidgetItem *current, QListWidgetItem *) { if (!current) { m_ui->lblName->clear(); m_ui->lblAuthor->clear(); m_ui->lblEmail->clear(); m_ui->lblLicense->clear(); m_ui->lblWebsite->clear(); m_ui->lblDescription->clear(); m_ui->lblCreated->clear(); m_ui->lblUpdated->clear(); m_ui->lblPreview->setPixmap(QPixmap::fromImage(QImage())); m_ui->listBundleContents->clear(); m_ui->bnEditBundle->setEnabled(false); m_currentBundle = 0; } else { QByteArray ba = current->data(Qt::UserRole).toByteArray(); KoResourceServer *bundleServer = KisResourceBundleServerProvider::instance()->resourceBundleServer(); - KisResourceBundle *bundle = bundleServer->resourceByMD5(ba); + KisResourceBundleSP bundle = bundleServer->resourceByMD5(ba); if (!bundle) { // Get it from the blacklisted bundles - Q_FOREACH (KisResourceBundle *b2, m_blacklistedBundles.values()) { + Q_FOREACH (KisResourceBundleSP b2, m_blacklistedBundles.values()) { if (b2->md5() == ba) { bundle = b2; break; } } } if (bundle) { QFontMetrics metrics(this->font()); m_currentBundle = bundle; m_ui->bnEditBundle->setEnabled(true); m_ui->lblName->setText(bundle->name()); m_ui->lblAuthor->setText(metrics.elidedText(bundle->getMeta("author"), Qt::ElideRight, m_ui->lblAuthor->width())); m_ui->lblAuthor->setToolTip(bundle->getMeta("author")); m_ui->lblEmail->setText(metrics.elidedText(bundle->getMeta("email"), Qt::ElideRight, m_ui->lblEmail->width())); m_ui->lblEmail->setToolTip(bundle->getMeta("email")); m_ui->lblLicense->setText(metrics.elidedText(bundle->getMeta("license"), Qt::ElideRight, m_ui->lblLicense->width())); m_ui->lblLicense->setToolTip(bundle->getMeta("license")); m_ui->lblWebsite->setText(metrics.elidedText(bundle->getMeta("website"), Qt::ElideRight, m_ui->lblWebsite->width())); m_ui->lblWebsite->setToolTip(bundle->getMeta("website")); m_ui->lblDescription->setPlainText(bundle->getMeta("description")); m_ui->lblCreated->setText(bundle->getMeta("created")); m_ui->lblUpdated->setText(bundle->getMeta("updated")); m_ui->lblPreview->setPixmap(QPixmap::fromImage(bundle->image().scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation))); m_ui->listBundleContents->clear(); Q_FOREACH (const QString & resType, bundle->resourceTypes()) { QTreeWidgetItem *toplevel = new QTreeWidgetItem(); if (resType == "gradients") { toplevel->setText(0, i18n("Gradients")); } else if (resType == "patterns") { toplevel->setText(0, i18n("Patterns")); } else if (resType == "brushes") { toplevel->setText(0, i18n("Brushes")); } else if (resType == "palettes") { toplevel->setText(0, i18n("Palettes")); } else if (resType == "workspaces") { toplevel->setText(0, i18n("Workspaces")); } else if (resType == "paintoppresets") { toplevel->setText(0, i18n("Brush Presets")); } else if (resType == "gamutmasks") { toplevel->setText(0, i18n("Gamut Masks")); } m_ui->listBundleContents->addTopLevelItem(toplevel); - Q_FOREACH (const KoResource *res, bundle->resources(resType)) { + Q_FOREACH (const KoResourceSP res, bundle->resources(resType)) { if (res) { QTreeWidgetItem *i = new QTreeWidgetItem(); i->setIcon(0, QIcon(QPixmap::fromImage(res->image()))); i->setText(0, res->name()); toplevel->addChild(i); } } } } else { m_currentBundle = 0; } } } void DlgBundleManager::itemSelected(QListWidgetItem *current) { itemSelected(current, 0); } void DlgBundleManager::editBundle() { if (m_currentBundle) { DlgCreateBundle dlg(m_currentBundle); m_activeBundles.remove(m_currentBundle->filename()); m_currentBundle = 0; if (dlg.exec() != QDialog::Accepted) { return; } m_currentBundle = m_resourceManager->saveBundle(dlg); refreshListData(); } } -void DlgBundleManager::fillListWidget(QList bundles, QListWidget *w) +void DlgBundleManager::fillListWidget(QList bundles, QListWidget *w) { w->setIconSize(QSize(ICON_SIZE, ICON_SIZE)); w->setSelectionMode(QAbstractItemView::MultiSelection); - Q_FOREACH (KisResourceBundle *bundle, bundles) { + Q_FOREACH (KisResourceBundleSP bundle, bundles) { QPixmap pixmap(ICON_SIZE, ICON_SIZE); pixmap.fill(Qt::gray); if (!bundle->image().isNull()) { QImage scaled = bundle->image().scaled(ICON_SIZE, ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation); int x = (ICON_SIZE - scaled.width()) / 2; int y = (ICON_SIZE - scaled.height()) / 2; QPainter gc(&pixmap); gc.drawImage(x, y, scaled); gc.end(); } QListWidgetItem *item = new QListWidgetItem(pixmap, bundle->name()); item->setData(Qt::UserRole, bundle->md5()); w->addItem(item); } } void DlgBundleManager::slotImportResource() { if (m_actionManager) { QObject *button = sender(); QString buttonName = button->objectName(); KisAction *action = 0; if (buttonName == "bnImportBundles") { action = m_actionManager->actionByName("import_bundles"); } else if (buttonName == "bnImportBrushes") { action = m_actionManager->actionByName("import_brushes"); } else if (buttonName == "bnImportGradients") { action = m_actionManager->actionByName("import_gradients"); } else if (buttonName == "bnImportPalettes") { action = m_actionManager->actionByName("import_palettes"); } else if (buttonName == "bnImportPatterns") { action = m_actionManager->actionByName("import_patterns"); } else if (buttonName == "bnImportPresets") { action = m_actionManager->actionByName("import_presets"); } else if (buttonName == "bnImportWorkspaces") { action = m_actionManager->actionByName("import_workspaces"); } else { warnUI << "Unhandled bundle manager import button " << buttonName; return; } action->trigger(); refreshListData(); } } void DlgBundleManager::slotCreateBundle() { if (m_actionManager) { KisAction *action = m_actionManager->actionByName("create_bundle"); action->trigger(); refreshListData(); } } void DlgBundleManager::slotDeleteBackupFiles() { if (m_actionManager) { KisAction *action = m_actionManager->actionByName("edit_blacklist_cleanup"); action->trigger(); } } void DlgBundleManager::slotOpenResourceFolder() { if (m_actionManager) { KisAction *action = m_actionManager->actionByName("open_resources_directory"); action->trigger(); } } diff --git a/plugins/extensions/resourcemanager/dlg_bundle_manager.h b/plugins/extensions/resourcemanager/dlg_bundle_manager.h index ba8c72cf08..81a3629901 100644 --- a/plugins/extensions/resourcemanager/dlg_bundle_manager.h +++ b/plugins/extensions/resourcemanager/dlg_bundle_manager.h @@ -1,72 +1,72 @@ /* * Copyright (c) 2014 Victor Lafon metabolic.ewilan@hotmail.fr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef DLG_BUNDLE_MANAGER_H #define DLG_BUNDLE_MANAGER_H #include #include #include "kis_action_manager.h" #include "resourcemanager.h" class KisResourceBundle; class QListWidget; class QListWidgetItem; namespace Ui { class WdgDlgBundleManager; } class DlgBundleManager : public KoDialog { Q_OBJECT public: explicit DlgBundleManager(ResourceManager *resourceManager, KisActionManager* actionMgr, QWidget *parent = 0); private Q_SLOTS: void accept() override; void addSelected(); void removeSelected(); void itemSelected(QListWidgetItem *current, QListWidgetItem *previous); void itemSelected(QListWidgetItem *current); void editBundle(); void slotImportResource(); void slotCreateBundle(); void slotDeleteBackupFiles(); void slotOpenResourceFolder(); private: QWidget *m_page; Ui::WdgDlgBundleManager *m_ui; - void fillListWidget(QList bundles, QListWidget *w); + void fillListWidget(QList bundles, QListWidget *w); void refreshListData(); - QMap m_blacklistedBundles; - QMap m_activeBundles; + QMap m_blacklistedBundles; + QMap m_activeBundles; - KisResourceBundle *m_currentBundle; + KisResourceBundleSP m_currentBundle; KisActionManager *m_actionManager; ResourceManager *m_resourceManager; }; #endif // DLG_BUNDLE_MANAGER_H diff --git a/plugins/extensions/resourcemanager/dlg_create_bundle.cpp b/plugins/extensions/resourcemanager/dlg_create_bundle.cpp index 09f4a14a95..dfb913ec88 100644 --- a/plugins/extensions/resourcemanager/dlg_create_bundle.cpp +++ b/plugins/extensions/resourcemanager/dlg_create_bundle.cpp @@ -1,467 +1,467 @@ /* * Copyright (c) 2014 Victor Lafon metabolic.ewilan@hotmail.fr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "dlg_create_bundle.h" #include "ui_wdgdlgcreatebundle.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisResourceBundle.h" #define ICON_SIZE 48 -DlgCreateBundle::DlgCreateBundle(KisResourceBundle *bundle, QWidget *parent) +DlgCreateBundle::DlgCreateBundle(KisResourceBundleSP bundle, QWidget *parent) : KoDialog(parent) , m_ui(new Ui::WdgDlgCreateBundle) , m_bundle(bundle) { m_page = new QWidget(); m_ui->setupUi(m_page); setMainWidget(m_page); setFixedSize(m_page->sizeHint()); setButtons(Ok | Cancel); setDefaultButton(Ok); setButtonText(Ok, i18n("Save")); connect(m_ui->bnSelectSaveLocation, SIGNAL(clicked()), SLOT(selectSaveLocation())); KoDocumentInfo info; info.updateParameters(); if (bundle) { setCaption(i18n("Edit Resource Bundle")); m_ui->lblSaveLocation->setText(QFileInfo(bundle->filename()).absolutePath()); m_ui->editBundleName->setText(bundle->name()); m_ui->editAuthor->setText(bundle->getMeta("author")); m_ui->editEmail->setText(bundle->getMeta("email")); m_ui->editLicense->setText(bundle->getMeta("license")); m_ui->editWebsite->setText(bundle->getMeta("website")); m_ui->editDescription->document()->setPlainText(bundle->getMeta("description")); m_ui->lblPreview->setPixmap(QPixmap::fromImage(bundle->image().scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation))); Q_FOREACH (const QString & resType, bundle->resourceTypes()) { if (resType == "gradients") { - Q_FOREACH (const KoResource *res, bundle->resources(resType)) { + Q_FOREACH (const KoResourceSP res, bundle->resources(resType)) { if (res) { m_selectedGradients << res->shortFilename(); } } } else if (resType == "patterns") { - Q_FOREACH (const KoResource *res, bundle->resources(resType)) { + Q_FOREACH (const KoResourceSP res, bundle->resources(resType)) { if (res) { m_selectedPatterns << res->shortFilename(); } } } else if (resType == "brushes") { - Q_FOREACH (const KoResource *res, bundle->resources(resType)) { + Q_FOREACH (const KoResourceSP res, bundle->resources(resType)) { if (res) { m_selectedBrushes << res->shortFilename(); } } } else if (resType == "palettes") { - Q_FOREACH (const KoResource *res, bundle->resources(resType)) { + Q_FOREACH (const KoResourceSP res, bundle->resources(resType)) { if (res) { m_selectedPalettes << res->shortFilename(); } } } else if (resType == "workspaces") { - Q_FOREACH (const KoResource *res, bundle->resources(resType)) { + Q_FOREACH (const KoResourceSP res, bundle->resources(resType)) { if (res) { m_selectedWorkspaces << res->shortFilename(); } } } else if (resType == "paintoppresets") { - Q_FOREACH (const KoResource *res, bundle->resources(resType)) { + Q_FOREACH (const KoResourceSP res, bundle->resources(resType)) { if (res) { m_selectedPresets << res->shortFilename(); } } } else if (resType == "gamutmasks") { - Q_FOREACH (const KoResource *res, bundle->resources(resType)) { + Q_FOREACH (const KoResourceSP res, bundle->resources(resType)) { if (res) { m_selectedGamutMasks << res->shortFilename(); } } } } } else { setCaption(i18n("Create Resource Bundle")); KisConfig cfg(true); m_ui->editAuthor->setText(cfg.readEntry("BundleAuthorName", info.authorInfo("creator"))); m_ui->editEmail->setText(cfg.readEntry("BundleAuthorEmail", info.authorInfo("email"))); m_ui->editWebsite->setText(cfg.readEntry("BundleWebsite", "http://")); m_ui->editLicense->setText(cfg.readEntry("BundleLicense", "CC-BY-SA")); m_ui->lblSaveLocation->setText(cfg.readEntry("BundleExportLocation", QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation))); } m_ui->bnAdd->setIcon(KisIconUtils::loadIcon("arrow-right")); connect(m_ui->bnAdd, SIGNAL(clicked()), SLOT(addSelected())); m_ui->bnRemove->setIcon(KisIconUtils::loadIcon("arrow-left")); connect(m_ui->bnRemove, SIGNAL(clicked()), SLOT(removeSelected())); m_ui->cmbResourceTypes->addItem(i18n("Brushes"), QString("brushes")); m_ui->cmbResourceTypes->addItem(i18n("Brush Presets"), QString("presets")); m_ui->cmbResourceTypes->addItem(i18n("Gradients"), QString("gradients")); m_ui->cmbResourceTypes->addItem(i18n("Gamut Masks"), QString("gamutmasks")); m_ui->cmbResourceTypes->addItem(i18n("Patterns"), QString("patterns")); m_ui->cmbResourceTypes->addItem(i18n("Palettes"), QString("palettes")); m_ui->cmbResourceTypes->addItem(i18n("Workspaces"), QString("workspaces")); connect(m_ui->cmbResourceTypes, SIGNAL(activated(int)), SLOT(resourceTypeSelected(int))); m_ui->tableAvailable->setIconSize(QSize(ICON_SIZE, ICON_SIZE)); m_ui->tableAvailable->setSelectionMode(QAbstractItemView::ExtendedSelection); m_ui->tableSelected->setIconSize(QSize(ICON_SIZE, ICON_SIZE)); m_ui->tableSelected->setSelectionMode(QAbstractItemView::ExtendedSelection); connect(m_ui->bnGetPreview, SIGNAL(clicked()), SLOT(getPreviewImage())); resourceTypeSelected(0); } DlgCreateBundle::~DlgCreateBundle() { delete m_ui; } QString DlgCreateBundle::bundleName() const { return m_ui->editBundleName->text().replace(" ", "_"); } QString DlgCreateBundle::authorName() const { return m_ui->editAuthor->text(); } QString DlgCreateBundle::email() const { return m_ui->editEmail->text(); } QString DlgCreateBundle::website() const { return m_ui->editWebsite->text(); } QString DlgCreateBundle::license() const { return m_ui->editLicense->text(); } QString DlgCreateBundle::description() const { return m_ui->editDescription->document()->toPlainText(); } QString DlgCreateBundle::saveLocation() const { return m_ui->lblSaveLocation->text(); } QString DlgCreateBundle::previewImage() const { return m_previewImage; } void DlgCreateBundle::accept() { QString name = m_ui->editBundleName->text().remove(" "); if (name.isEmpty()) { m_ui->editBundleName->setStyleSheet(QString(" border: 1px solid red")); QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("The resource bundle name cannot be empty.")); return; } else { QFileInfo fileInfo(m_ui->lblSaveLocation->text() + "/" + name + ".bundle"); if (fileInfo.exists() && !m_bundle) { m_ui->editBundleName->setStyleSheet("border: 1px solid red"); QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("A bundle with this name already exists.")); return; } else { if (!m_bundle) { KisConfig cfg(false); cfg.writeEntry("BunleExportLocation", m_ui->lblSaveLocation->text()); cfg.writeEntry("BundleAuthorName", m_ui->editAuthor->text()); cfg.writeEntry("BundleAuthorEmail", m_ui->editEmail->text()); cfg.writeEntry("BundleWebsite", m_ui->editWebsite->text()); cfg.writeEntry("BundleLicense", m_ui->editLicense->text()); } KoDialog::accept(); } } } void DlgCreateBundle::selectSaveLocation() { KoFileDialog dialog(this, KoFileDialog::OpenDirectory, "resourcebundlesavelocation"); dialog.setDefaultDir(m_ui->lblSaveLocation->text()); dialog.setCaption(i18n("Select a directory to save the bundle")); QString location = dialog.filename(); m_ui->lblSaveLocation->setText(location); } void DlgCreateBundle::addSelected() { int row = m_ui->tableAvailable->currentRow(); Q_FOREACH (QListWidgetItem *item, m_ui->tableAvailable->selectedItems()) { m_ui->tableSelected->addItem(m_ui->tableAvailable->takeItem(m_ui->tableAvailable->row(item))); QString resourceType = m_ui->cmbResourceTypes->itemData(m_ui->cmbResourceTypes->currentIndex()).toString(); if (resourceType == "brushes") { m_selectedBrushes.append(item->data(Qt::UserRole).toString()); } else if (resourceType == "presets") { m_selectedPresets.append(item->data(Qt::UserRole).toString()); } else if (resourceType == "gradients") { m_selectedGradients.append(item->data(Qt::UserRole).toString()); } else if (resourceType == "patterns") { m_selectedPatterns.append(item->data(Qt::UserRole).toString()); } else if (resourceType == "palettes") { m_selectedPalettes.append(item->data(Qt::UserRole).toString()); } else if (resourceType == "workspaces") { m_selectedWorkspaces.append(item->data(Qt::UserRole).toString()); } else if (resourceType == "gamutmasks") { m_selectedGamutMasks.append(item->data(Qt::UserRole).toString()); } } m_ui->tableAvailable->setCurrentRow(row); } void DlgCreateBundle::removeSelected() { int row = m_ui->tableSelected->currentRow(); Q_FOREACH (QListWidgetItem *item, m_ui->tableSelected->selectedItems()) { m_ui->tableAvailable->addItem(m_ui->tableSelected->takeItem(m_ui->tableSelected->row(item))); QString resourceType = m_ui->cmbResourceTypes->itemData(m_ui->cmbResourceTypes->currentIndex()).toString(); if (resourceType == "brushes") { m_selectedBrushes.removeAll(item->data(Qt::UserRole).toString()); } else if (resourceType == "presets") { m_selectedPresets.removeAll(item->data(Qt::UserRole).toString()); } else if (resourceType == "gradients") { m_selectedGradients.removeAll(item->data(Qt::UserRole).toString()); } else if (resourceType == "patterns") { m_selectedPatterns.removeAll(item->data(Qt::UserRole).toString()); } else if (resourceType == "palettes") { m_selectedPalettes.removeAll(item->data(Qt::UserRole).toString()); } else if (resourceType == "workspaces") { m_selectedWorkspaces.removeAll(item->data(Qt::UserRole).toString()); } else if (resourceType == "gamutmasks") { m_selectedGamutMasks.removeAll(item->data(Qt::UserRole).toString()); } } m_ui->tableSelected->setCurrentRow(row); } QPixmap imageToIcon(const QImage &img) { QPixmap pixmap(ICON_SIZE, ICON_SIZE); pixmap.fill(); QImage scaled = img.scaled(ICON_SIZE, ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation); int x = (ICON_SIZE - scaled.width()) / 2; int y = (ICON_SIZE - scaled.height()) / 2; QPainter gc(&pixmap); gc.drawImage(x, y, scaled); gc.end(); return pixmap; } void DlgCreateBundle::resourceTypeSelected(int idx) { QString resourceType = m_ui->cmbResourceTypes->itemData(idx).toString(); m_ui->tableAvailable->clear(); m_ui->tableSelected->clear(); if (resourceType == "brushes") { KisBrushResourceServer *server = KisBrushServer::instance()->brushServer(); Q_FOREACH (KisBrushSP res, server->resources()) { QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); item->setData(Qt::UserRole, res->shortFilename()); if (m_selectedBrushes.contains(res->shortFilename())) { m_ui->tableSelected->addItem(item); } else { m_ui->tableAvailable->addItem(item); } } } else if (resourceType == "presets") { KisPaintOpPresetResourceServer* server = KisResourceServerProvider::instance()->paintOpPresetServer(); Q_FOREACH (KisPaintOpPresetSP res, server->resources()) { QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); item->setData(Qt::UserRole, res->shortFilename()); if (m_selectedPresets.contains(res->shortFilename())) { m_ui->tableSelected->addItem(item); } else { m_ui->tableAvailable->addItem(item); } } } else if (resourceType == "gradients") { KoResourceServer* server = KoResourceServerProvider::instance()->gradientServer(); - Q_FOREACH (KoResource *res, server->resources()) { + Q_FOREACH (KoResourceSP res, server->resources()) { if (res->filename()!="Foreground to Transparent" && res->filename()!="Foreground to Background") { //technically we should read from the file-name whether or not the file can be opened, but this works for now. The problem is making sure that bundle-resource know where they are stored.// //dbgKrita<filename(); QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); item->setData(Qt::UserRole, res->shortFilename()); if (m_selectedGradients.contains(res->shortFilename())) { m_ui->tableSelected->addItem(item); } else { m_ui->tableAvailable->addItem(item); } } } } else if (resourceType == "patterns") { KoResourceServer* server = KoResourceServerProvider::instance()->patternServer(); - Q_FOREACH (KoResource *res, server->resources()) { + Q_FOREACH (KoResourceSP res, server->resources()) { QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); item->setData(Qt::UserRole, res->shortFilename()); if (m_selectedPatterns.contains(res->shortFilename())) { m_ui->tableSelected->addItem(item); } else { m_ui->tableAvailable->addItem(item); } } } else if (resourceType == "palettes") { KoResourceServer* server = KoResourceServerProvider::instance()->paletteServer(); - Q_FOREACH (KoResource *res, server->resources()) { + Q_FOREACH (KoResourceSP res, server->resources()) { QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); item->setData(Qt::UserRole, res->shortFilename()); if (m_selectedPalettes.contains(res->shortFilename())) { m_ui->tableSelected->addItem(item); } else { m_ui->tableAvailable->addItem(item); } } } else if (resourceType == "workspaces") { KoResourceServer* server = KisResourceServerProvider::instance()->workspaceServer(); - Q_FOREACH (KoResource *res, server->resources()) { + Q_FOREACH (KoResourceSP res, server->resources()) { QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); item->setData(Qt::UserRole, res->shortFilename()); if (m_selectedWorkspaces.contains(res->shortFilename())) { m_ui->tableSelected->addItem(item); } else { m_ui->tableAvailable->addItem(item); } } } else if (resourceType == "gamutmasks") { KoResourceServer* server = KoResourceServerProvider::instance()->gamutMaskServer(); - Q_FOREACH (KoResource *res, server->resources()) { + Q_FOREACH (KoResourceSP res, server->resources()) { QListWidgetItem *item = new QListWidgetItem(imageToIcon(res->image()), res->name()); item->setData(Qt::UserRole, res->shortFilename()); if (m_selectedGamutMasks.contains(res->shortFilename())) { m_ui->tableSelected->addItem(item); } else { m_ui->tableAvailable->addItem(item); } } } } void DlgCreateBundle::getPreviewImage() { KoFileDialog dialog(this, KoFileDialog::OpenFile, "BundlePreviewImage"); dialog.setCaption(i18n("Select file to use as bundle icon")); dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); dialog.setMimeTypeFilters(KisImportExportManager::supportedMimeTypes(KisImportExportManager::Import)); m_previewImage = dialog.filename(); QImage img(m_previewImage); img = img.scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation); m_ui->lblPreview->setPixmap(QPixmap::fromImage(img)); } diff --git a/plugins/extensions/resourcemanager/dlg_create_bundle.h b/plugins/extensions/resourcemanager/dlg_create_bundle.h index 9253ecd74e..4e200616ea 100644 --- a/plugins/extensions/resourcemanager/dlg_create_bundle.h +++ b/plugins/extensions/resourcemanager/dlg_create_bundle.h @@ -1,83 +1,83 @@ /* * Copyright (c) 2014 Victor Lafon metabolic.ewilan@hotmail.fr * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KOBUNDLECREATIONWIDGET_H #define KOBUNDLECREATIONWIDGET_H #include -class KisResourceBundle; +#include namespace Ui { class WdgDlgCreateBundle; } class DlgCreateBundle : public KoDialog { Q_OBJECT public: - explicit DlgCreateBundle(KisResourceBundle *bundle = 0, QWidget *parent = 0); + explicit DlgCreateBundle(KisResourceBundleSP bundle = nullptr, QWidget *parent = 0); ~DlgCreateBundle() override; QString bundleName() const; QString authorName() const; QString email() const; QString website() const; QString license() const; QString description() const; QString saveLocation() const; QString previewImage() const; QStringList selectedBrushes() const { return m_selectedBrushes; } QStringList selectedPresets() const { return m_selectedPresets; } QStringList selectedGradients() const { return m_selectedGradients; } QStringList selectedPatterns() const { return m_selectedPatterns; } QStringList selectedPalettes() const { return m_selectedPalettes; } QStringList selectedWorkspaces() const { return m_selectedWorkspaces; } QStringList selectedGamutMasks() const { return m_selectedGamutMasks; } private Q_SLOTS: void accept() override; void selectSaveLocation(); void addSelected(); void removeSelected(); void resourceTypeSelected(int idx); void getPreviewImage(); private: QWidget *m_page; Ui::WdgDlgCreateBundle *m_ui; QStringList m_selectedBrushes; QStringList m_selectedPresets; QStringList m_selectedGradients; QStringList m_selectedPatterns; QStringList m_selectedPalettes; QStringList m_selectedWorkspaces; QStringList m_selectedGamutMasks; QString m_previewImage; - KisResourceBundle *m_bundle; + KisResourceBundleSP m_bundle; }; #endif // KOBUNDLECREATIONWIDGET_H diff --git a/plugins/extensions/resourcemanager/resourcemanager.cpp b/plugins/extensions/resourcemanager/resourcemanager.cpp index 517038326f..299cbcd0fe 100644 --- a/plugins/extensions/resourcemanager/resourcemanager.cpp +++ b/plugins/extensions/resourcemanager/resourcemanager.cpp @@ -1,335 +1,335 @@ /* * resourcemanager.cc -- Part of Krita * * Copyright (c) 2004 Boudewijn Rempt (boud@valdyas.org) * * 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 "resourcemanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dlg_bundle_manager.h" #include "dlg_create_bundle.h" #include #include "krita_container_utils.h" class ResourceManager::Private { public: Private() { brushServer = KisBrushServer::instance()->brushServer(); paintopServer = KisResourceServerProvider::instance()->paintOpPresetServer(); gradientServer = KoResourceServerProvider::instance()->gradientServer(); patternServer = KoResourceServerProvider::instance()->patternServer(); paletteServer = KoResourceServerProvider::instance()->paletteServer(); workspaceServer = KisResourceServerProvider::instance()->workspaceServer(); gamutMaskServer = KoResourceServerProvider::instance()->gamutMaskServer(); } KisBrushResourceServer* brushServer; KisPaintOpPresetResourceServer * paintopServer; KoResourceServer* gradientServer; KoResourceServer *patternServer; KoResourceServer* paletteServer; KoResourceServer* workspaceServer; KoResourceServer* gamutMaskServer; }; K_PLUGIN_FACTORY_WITH_JSON(ResourceManagerFactory, "kritaresourcemanager.json", registerPlugin();) ResourceManager::ResourceManager(QObject *parent, const QVariantList &) : KisActionPlugin(parent) , d(new Private()) { KisAction *action = new KisAction(i18n("Import Bundles..."), this); addAction("import_bundles", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportBundles())); action = new KisAction(i18n("Import Brushes..."), this); addAction("import_brushes", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportBrushes())); action = new KisAction(i18n("Import Gradients..."), this); addAction("import_gradients", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportGradients())); action = new KisAction(i18n("Import Palettes..."), this); addAction("import_palettes", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportPalettes())); action = new KisAction(i18n("Import Patterns..."), this); addAction("import_patterns", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportPatterns())); action = new KisAction(i18n("Import Presets..."), this); addAction("import_presets", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportPresets())); action = new KisAction(i18n("Import Workspaces..."), this); addAction("import_workspaces", action); connect(action, SIGNAL(triggered()), this, SLOT(slotImportWorkspaces())); action = new KisAction(i18n("Create Resource Bundle..."), this); addAction("create_bundle", action); connect(action, SIGNAL(triggered()), this, SLOT(slotCreateBundle())); action = new KisAction(i18n("Manage Resources..."), this); addAction("manage_bundles", action); connect(action, SIGNAL(triggered()), this, SLOT(slotManageBundles())); } ResourceManager::~ResourceManager() { } void ResourceManager::slotCreateBundle() { DlgCreateBundle dlgCreateBundle; if (dlgCreateBundle.exec() != QDialog::Accepted) { return; } saveBundle(dlgCreateBundle); } -KisResourceBundle *ResourceManager::saveBundle(const DlgCreateBundle &dlgCreateBundle) +KisResourceBundleSP ResourceManager::saveBundle(const DlgCreateBundle &dlgCreateBundle) { QString bundlePath = dlgCreateBundle.saveLocation() + "/" + dlgCreateBundle.bundleName() + ".bundle"; - KisResourceBundle *newBundle = new KisResourceBundle(bundlePath); + KisResourceBundleSP newBundle(new KisResourceBundle(bundlePath)); newBundle->addMeta("name", dlgCreateBundle.bundleName()); newBundle->addMeta("author", dlgCreateBundle.authorName()); newBundle->addMeta("email", dlgCreateBundle.email()); newBundle->addMeta("license", dlgCreateBundle.license()); newBundle->addMeta("website", dlgCreateBundle.website()); newBundle->addMeta("description", dlgCreateBundle.description()); newBundle->setThumbnail(dlgCreateBundle.previewImage()); QStringList res = dlgCreateBundle.selectedBrushes(); Q_FOREACH (const QString &r, res) { - KoResource *res = d->brushServer->resourceByFilename(r).data(); + KoResourceSP res = d->brushServer->resourceByFilename(r); newBundle->addResource("brushes", res->filename(), d->brushServer->assignedTagsList(res), res->md5()); } res = dlgCreateBundle.selectedGradients(); Q_FOREACH (const QString &r, res) { - KoResource *res = d->gradientServer->resourceByFilename(r); + KoResourceSP res = d->gradientServer->resourceByFilename(r); newBundle->addResource("gradients", res->filename(), d->gradientServer->assignedTagsList(res), res->md5()); } res = dlgCreateBundle.selectedPalettes(); Q_FOREACH (const QString &r, res) { - KoResource *res = d->paletteServer->resourceByFilename(r); + KoResourceSP res = d->paletteServer->resourceByFilename(r); newBundle->addResource("palettes", res->filename(), d->paletteServer->assignedTagsList(res), res->md5()); } res = dlgCreateBundle.selectedPatterns(); Q_FOREACH (const QString &r, res) { - KoResource *res = d->patternServer->resourceByFilename(r); + KoResourceSP res = d->patternServer->resourceByFilename(r); newBundle->addResource("patterns", res->filename(), d->patternServer->assignedTagsList(res), res->md5()); } res = dlgCreateBundle.selectedPresets(); Q_FOREACH (const QString &r, res) { KisPaintOpPresetSP preset = d->paintopServer->resourceByFilename(r); - KoResource *res = preset.data(); + KoResourceSP res = preset; newBundle->addResource("paintoppresets", res->filename(), d->paintopServer->assignedTagsList(res), res->md5()); KisPaintOpSettingsSP settings = preset->settings(); QStringList requiredFiles = settings->getStringList(KisPaintOpUtils::RequiredBrushFilesListTag); requiredFiles << settings->getString(KisPaintOpUtils::RequiredBrushFileTag); KritaUtils::makeContainerUnique(requiredFiles); Q_FOREACH (const QString &brushFile, requiredFiles) { - KisBrush *brush = d->brushServer->resourceByFilename(brushFile).data(); + KisBrushSP brush = d->brushServer->resourceByFilename(brushFile); if (brush) { newBundle->addResource("brushes", brushFile, d->brushServer->assignedTagsList(brush), brush->md5()); } else { qWarning() << "There is no brush with name" << brushFile; } } } res = dlgCreateBundle.selectedWorkspaces(); Q_FOREACH (const QString &r, res) { - KoResource *res = d->workspaceServer->resourceByFilename(r); + KoResourceSP res = d->workspaceServer->resourceByFilename(r); newBundle->addResource("workspaces", res->filename(), d->workspaceServer->assignedTagsList(res), res->md5()); } res = dlgCreateBundle.selectedGamutMasks(); Q_FOREACH (const QString &r, res) { - KoResource *res = d->gamutMaskServer->resourceByFilename(r); + KoResourceSP res = d->gamutMaskServer->resourceByFilename(r); newBundle->addResource("gamutmasks", res->filename(), d->gamutMaskServer->assignedTagsList(res), res->md5()); } newBundle->addMeta("fileName", bundlePath); newBundle->addMeta("created", QDate::currentDate().toString("dd/MM/yyyy")); if (!newBundle->save()) { QMessageBox::critical(viewManager()->mainWindow(), i18nc("@title:window", "Krita"), i18n("Could not create the new bundle.")); } else { newBundle->setValid(true); if (QDir(KisResourceBundleServerProvider::instance()->resourceBundleServer()->saveLocation()) != QDir(QFileInfo(bundlePath).path())) { newBundle->setFilename(KisResourceBundleServerProvider::instance()->resourceBundleServer()->saveLocation() + "/" + dlgCreateBundle.bundleName() + ".bundle"); } if (KisResourceBundleServerProvider::instance()->resourceBundleServer()->resourceByName(newBundle->name())) { KisResourceBundleServerProvider::instance()->resourceBundleServer()->removeResourceFromServer( KisResourceBundleServerProvider::instance()->resourceBundleServer()->resourceByName(newBundle->name())); } KisResourceBundleServerProvider::instance()->resourceBundleServer()->addResource(newBundle, true); newBundle->load(); } return newBundle; } void ResourceManager::slotManageBundles() { DlgBundleManager* dlg = new DlgBundleManager(this, viewManager()->actionManager()); if (dlg->exec() != QDialog::Accepted) { return; } } QStringList ResourceManager::importResources(const QString &title, const QStringList &mimes) const { KoFileDialog dialog(viewManager()->mainWindow(), KoFileDialog::OpenFiles, "krita_resources"); dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); dialog.setCaption(title); dialog.setMimeTypeFilters(mimes); return dialog.filenames(); } void ResourceManager::slotImportBrushes() { QStringList resources = importResources(i18n("Import Brushes"), QStringList() << "image/x-gimp-brush" << "image/x-gimp-x-gimp-brush-animated" << "image/x-adobe-brushlibrary" << "image/png" << "image/svg+xml"); Q_FOREACH (const QString &res, resources) { d->brushServer->importResourceFile(res); } } void ResourceManager::slotImportPresets() { QStringList resources = importResources(i18n("Import Presets"), QStringList() << "application/x-krita-paintoppreset"); Q_FOREACH (const QString &res, resources) { d->paintopServer->importResourceFile(res); } } void ResourceManager::slotImportGradients() { QStringList resources = importResources(i18n("Import Gradients"), QStringList() << "image/svg+xml" << "application/x-gimp-gradient" << "application/x-karbon-gradient"); Q_FOREACH (const QString &res, resources) { d->gradientServer->importResourceFile(res); } } void ResourceManager::slotImportBundles() { QStringList resources = importResources(i18n("Import Bundles"), QStringList() << "application/x-krita-bundle"); Q_FOREACH (const QString &res, resources) { - KisResourceBundle *bundle = KisResourceBundleServerProvider::instance()->resourceBundleServer()->createResource(res); + KisResourceBundleSP bundle = KisResourceBundleServerProvider::instance()->resourceBundleServer()->createResource(res); bundle->load(); if (bundle->valid()) { if (!bundle->install()) { QMessageBox::warning(0, i18nc("@title:window", "Krita"), i18n("Could not install the resources for bundle %1.", res)); } } else { QMessageBox::warning(0, i18nc("@title:window", "Krita"), i18n("Could not load bundle %1.", res)); } QFileInfo fi(res); QString newFilename = KisResourceBundleServerProvider::instance()->resourceBundleServer()->saveLocation() + fi.baseName() + bundle->defaultFileExtension(); QFileInfo fileInfo(newFilename); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(KisResourceBundleServerProvider::instance()->resourceBundleServer()->saveLocation() + fi.baseName() + QString("%1").arg(i) + bundle->defaultFileExtension()); i++; } bundle->setFilename(fileInfo.filePath()); QFile::copy(res, newFilename); KisResourceBundleServerProvider::instance()->resourceBundleServer()->addResource(bundle, false); } } void ResourceManager::slotImportPatterns() { QStringList resources = importResources(i18n("Import Patterns"), QStringList() << "image/png" << "image/svg+xml" << "application/x-gimp-pattern" << "image/jpeg" << "image/tiff" << "image/bmp" << "image/xpg"); Q_FOREACH (const QString &res, resources) { d->patternServer->importResourceFile(res); } } void ResourceManager::slotImportPalettes() { QStringList resources = importResources(i18n("Import Palettes"), QStringList() << "image/x-gimp-color-palette"); Q_FOREACH (const QString &res, resources) { d->paletteServer->importResourceFile(res); } } void ResourceManager::slotImportWorkspaces() { QStringList resources = importResources(i18n("Import Workspaces"), QStringList() << "application/x-krita-workspace"); Q_FOREACH (const QString &res, resources) { d->workspaceServer->importResourceFile(res); } } #include "resourcemanager.moc" diff --git a/plugins/extensions/resourcemanager/resourcemanager.h b/plugins/extensions/resourcemanager/resourcemanager.h index 968fed07a0..3c7057b903 100644 --- a/plugins/extensions/resourcemanager/resourcemanager.h +++ b/plugins/extensions/resourcemanager/resourcemanager.h @@ -1,63 +1,63 @@ /* * resourcemanager.h -- Part of Krita * * Copyright (c) 2014 Boudewijn Rempt (boud@valdyas.org) * * 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 RESOURCEMANAGER_H #define RESOURCEMANAGER_H #include #include #include #include #include #include "KisResourceBundle.h" #include "dlg_create_bundle.h" class ResourceManager : public KisActionPlugin { Q_OBJECT public: ResourceManager(QObject *parent, const QVariantList &); ~ResourceManager() override; - KisResourceBundle *saveBundle(const DlgCreateBundle &dlgCreateBundle); + KisResourceBundleSP saveBundle(const DlgCreateBundle &dlgCreateBundle); private Q_SLOTS: void slotCreateBundle(); void slotManageBundles(); void slotImportBrushes(); void slotImportGradients(); void slotImportPalettes(); void slotImportPatterns(); void slotImportPresets(); void slotImportWorkspaces(); void slotImportBundles(); private: QStringList importResources(const QString &title, const QStringList &mimes) const; class Private; QScopedPointer d; }; #endif // RESOURCEMANAGER_H diff --git a/plugins/filters/gradientmap/gradientmap.cpp b/plugins/filters/gradientmap/gradientmap.cpp index a2d504c979..d9c4de40c9 100644 --- a/plugins/filters/gradientmap/gradientmap.cpp +++ b/plugins/filters/gradientmap/gradientmap.cpp @@ -1,125 +1,125 @@ /* * 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 "QObject" #include "gradientmap.h" #include #include #include "krita_filter_gradient_map.h" #include "KoResourceServerProvider.h" #include "kis_config_widget.h" #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KritaGradientMapFactory, "kritagradientmap.json", registerPlugin();) KritaGradientMapConfigWidget::KritaGradientMapConfigWidget(QWidget *parent, KisPaintDeviceSP dev, Qt::WindowFlags f) : KisConfigWidget(parent, f) { Q_UNUSED(dev) m_page = new WdgGradientMap(this); QHBoxLayout *l = new QHBoxLayout(this); Q_CHECK_PTR(l); l->addWidget(m_page); l->setContentsMargins(0, 0, 0, 0); KoResourceServerProvider *serverProvider = KoResourceServerProvider::instance(); QSharedPointer gradientResourceAdapter( new KoResourceServerAdapter(serverProvider->gradientServer())); m_gradientChangedCompressor = new KisSignalCompressor(100, KisSignalCompressor::FIRST_ACTIVE); m_gradientPopUp = new KoResourcePopupAction(gradientResourceAdapter, m_page->btnGradientChooser); - m_activeGradient = KoStopGradient::fromQGradient(dynamic_cast(gradientResourceAdapter->resources().first())->toQGradient()); + m_activeGradient = KoStopGradient::fromQGradient(gradientResourceAdapter->resources().first().dynamicCast()->toQGradient()); m_page->gradientEditor->setGradient(m_activeGradient); m_page->gradientEditor->setCompactMode(true); m_page->gradientEditor->setEnabled(true); m_page->btnGradientChooser->setDefaultAction(m_gradientPopUp); m_page->btnGradientChooser->setPopupMode(QToolButton::InstantPopup); connect(m_gradientPopUp, SIGNAL(resourceSelected(QSharedPointer)), this, SLOT(setAbstractGradientToEditor())); connect(m_page->gradientEditor, SIGNAL(sigGradientChanged()), m_gradientChangedCompressor, SLOT(start())); connect(m_gradientChangedCompressor, SIGNAL(timeout()), this, SIGNAL(sigConfigurationItemChanged())); } KritaGradientMapConfigWidget::~KritaGradientMapConfigWidget() { delete m_page; } void KritaGradientMapConfigWidget::setAbstractGradientToEditor() { QSharedPointer bg = qSharedPointerDynamicCast( m_gradientPopUp->currentBackground()); m_activeGradient = KoStopGradient::fromQGradient(bg->gradient()); m_page->gradientEditor->setGradient(m_activeGradient); } KisPropertiesConfigurationSP KritaGradientMapConfigWidget::configuration() const { KisFilterConfigurationSP cfg = new KisFilterConfiguration("gradientmap", 2); if (m_activeGradient) { QDomDocument doc; QDomElement elt = doc.createElement("gradient"); m_activeGradient->toXML(doc, elt); doc.appendChild(elt); cfg->setProperty("gradientXML", doc.toString()); } return cfg; } //----------------------------- void KritaGradientMapConfigWidget::setConfiguration(const KisPropertiesConfigurationSP config) { Q_ASSERT(config); QDomDocument doc; if (config->hasProperty("gradientXML")) { doc.setContent(config->getString("gradientXML", "")); KoStopGradient gradient = KoStopGradient::fromXML(doc.firstChildElement()); if (gradient.stops().size()>0) { m_activeGradient->setStops(gradient.stops()); } } } void KritaGradientMapConfigWidget::setView(KisViewManager *view) { Q_UNUSED(view) } //------------------------------ KritaGradientMap::KritaGradientMap(QObject *parent, const QVariantList &) : QObject(parent) { KisFilterRegistry::instance()->add(KisFilterSP(new KritaFilterGradientMap())); } KritaGradientMap::~KritaGradientMap() { } //----------------------------- #include "gradientmap.moc" diff --git a/plugins/filters/gradientmap/gradientmap.h b/plugins/filters/gradientmap/gradientmap.h index bcaf3eaa29..18595aaa1b 100644 --- a/plugins/filters/gradientmap/gradientmap.h +++ b/plugins/filters/gradientmap/gradientmap.h @@ -1,83 +1,83 @@ /* * This file is part of Krita * * 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. */ #pragma once #include "QObject" #include "ui_wdg_gradientmap.h" #include "kis_properties_configuration.h" #include "filter/kis_color_transformation_configuration.h" #include "kis_config_widget.h" #include #include #include class WdgGradientMap : public QWidget, public Ui::WdgGradientMap { Q_OBJECT public: WdgGradientMap(QWidget *parent) : QWidget(parent) { setupUi(this); } }; class KritaGradientMapFilterConfiguration : public KisColorTransformationConfiguration { public: KritaGradientMapFilterConfiguration(); ~KritaGradientMapFilterConfiguration() override; - virtual void setGradient(const KoResource* gradient); + virtual void setGradient(const KoResourceSP gradient); - virtual const KoResource* gradient() const; + virtual const KoResourceSP gradient() const; private: KoResource const* m_gradient; }; class KritaGradientMapConfigWidget : public KisConfigWidget { Q_OBJECT public: KritaGradientMapConfigWidget(QWidget *parent, KisPaintDeviceSP dev, Qt::WindowFlags f = 0); ~KritaGradientMapConfigWidget() override; KisPropertiesConfigurationSP configuration() const override; void setConfiguration(const KisPropertiesConfigurationSP config) override; WdgGradientMap *m_page; KoResourcePopupAction *m_gradientPopUp; KisSignalCompressor *m_gradientChangedCompressor; - KoStopGradient *m_activeGradient; + KoStopGradientSP m_activeGradient; void setView(KisViewManager *view) override; private Q_SLOTS: void setAbstractGradientToEditor(); }; class KritaGradientMap : public QObject { Q_OBJECT public: KritaGradientMap(QObject *parent, const QVariantList &); ~KritaGradientMap() override; }; diff --git a/plugins/filters/gradientmap/krita_filter_gradient_map.cpp b/plugins/filters/gradientmap/krita_filter_gradient_map.cpp index 961d3166a7..3db418e577 100644 --- a/plugins/filters/gradientmap/krita_filter_gradient_map.cpp +++ b/plugins/filters/gradientmap/krita_filter_gradient_map.cpp @@ -1,106 +1,106 @@ /* * This file is part of the KDE project * * Copyright (c) 2016 Spencer Brown * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "krita_filter_gradient_map.h" #include #include #include #include #include #include #include "kis_config_widget.h" #include #include #include #include #include #include "gradientmap.h" #include KritaFilterGradientMap::KritaFilterGradientMap() : KisFilter(id(), FiltersCategoryMapId, i18n("&Gradient Map...")) { setColorSpaceIndependence(FULLY_INDEPENDENT); setShowConfigurationWidget(true); setSupportsLevelOfDetail(true); setSupportsPainting(true); setSupportsAdjustmentLayers(true); setSupportsThreading(true); } void KritaFilterGradientMap::processImpl(KisPaintDeviceSP device, const QRect& applyRect, const KisFilterConfigurationSP config, KoUpdater *progressUpdater) const { Q_ASSERT(!device.isNull()); QDomDocument doc; if (config->version()==1) { QDomElement elt = doc.createElement("gradient"); - KoAbstractGradient *gradientAb = KoResourceServerProvider::instance()->gradientServer()->resourceByName(config->getString("gradientName")); + KoAbstractGradientSP gradientAb = KoResourceServerProvider::instance()->gradientServer()->resourceByName(config->getString("gradientName")); if (!gradientAb) { qWarning() << "Could not find gradient" << config->getString("gradientName"); } gradientAb = KoResourceServerProvider::instance()->gradientServer()->resources().first(); KoStopGradient::fromQGradient(gradientAb->toQGradient())->toXML(doc, elt); doc.appendChild(elt); } else { doc.setContent(config->getString("gradientXML", "")); } KoStopGradient gradient = KoStopGradient::fromXML(doc.firstChildElement()); KoColor outColor(Qt::white, device->colorSpace()); KisSequentialIteratorProgress it(device, applyRect, progressUpdater); quint8 grey; const int pixelSize = device->colorSpace()->pixelSize(); while (it.nextPixel()) { grey = device->colorSpace()->intensity8(it.oldRawData()); gradient.colorAt(outColor,(qreal)grey/255); outColor.setOpacity(qMin(KoColor(it.oldRawData(), device->colorSpace()).opacityF(), outColor.opacityF())); outColor.convertTo(device->colorSpace()); memcpy(it.rawData(), outColor.data(), pixelSize); } } KisFilterConfigurationSP KritaFilterGradientMap::factoryConfiguration() const { KisFilterConfigurationSP config = new KisFilterConfiguration("gradientmap", 2); - KoAbstractGradient *gradient = KoResourceServerProvider::instance()->gradientServer()->resources().first(); + KoAbstractGradientSP gradient = KoResourceServerProvider::instance()->gradientServer()->resources().first(); KoStopGradient stopGradient; stopGradient.fromQGradient(gradient->toQGradient()); QDomDocument doc; QDomElement elt = doc.createElement("gradient"); stopGradient.toXML(doc, elt); doc.appendChild(elt); config->setProperty("gradientXML", doc.toString()); return config; } KisConfigWidget * KritaFilterGradientMap::createConfigurationWidget(QWidget * parent, const KisPaintDeviceSP dev) const { return new KritaGradientMapConfigWidget(parent, dev); } diff --git a/plugins/generators/pattern/kis_wdg_pattern.cpp b/plugins/generators/pattern/kis_wdg_pattern.cpp index 2f16ae2548..3276ad0989 100644 --- a/plugins/generators/pattern/kis_wdg_pattern.cpp +++ b/plugins/generators/pattern/kis_wdg_pattern.cpp @@ -1,70 +1,70 @@ /* * This file is part of Krita * * Copyright (c) 2006 Cyrille Berger * * 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_wdg_pattern.h" #include #include #include #include #include #include #include #include #include "ui_wdgpatternoptions.h" KisWdgPattern::KisWdgPattern(QWidget* parent) : KisConfigWidget(parent) { m_widget = new Ui_WdgPatternOptions(); m_widget->setupUi(this); m_widget->lblPattern->setVisible(false); m_widget->lblColor->setVisible(false); m_widget->bnColor->setVisible(false); } KisWdgPattern::~KisWdgPattern() { delete m_widget; } void KisWdgPattern::setConfiguration(const KisPropertiesConfigurationSP config) { KoResourceServer *rserver = KoResourceServerProvider::instance()->patternServer(); - KoPattern *pattern = rserver->resourceByName(config->getString("pattern", "Grid01.pat")); + KoPatternSP pattern = rserver->resourceByName(config->getString("pattern", "Grid01.pat")); if (pattern) { widget()->patternChooser->setCurrentPattern(pattern); } } KisPropertiesConfigurationSP KisWdgPattern::configuration() const { KisFilterConfigurationSP config = new KisFilterConfiguration("pattern", 1); QVariant v; v.setValue(widget()->patternChooser->currentResource()->name()); config->setProperty("pattern", v); return config; } diff --git a/plugins/generators/pattern/patterngenerator.cpp b/plugins/generators/pattern/patterngenerator.cpp index 09dffd5cec..ca3d671635 100644 --- a/plugins/generators/pattern/patterngenerator.cpp +++ b/plugins/generators/pattern/patterngenerator.cpp @@ -1,121 +1,121 @@ /* * This file is part of the KDE project * * Copyright (c) 2008 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 "patterngenerator.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_wdg_pattern.h" #include "ui_wdgpatternoptions.h" K_PLUGIN_FACTORY_WITH_JSON(KritaPatternGeneratorFactory, "kritapatterngenerator.json", registerPlugin();) KritaPatternGenerator::KritaPatternGenerator(QObject *parent, const QVariantList &) : QObject(parent) { KisGeneratorRegistry::instance()->add(new KoPatternGenerator()); } KritaPatternGenerator::~KritaPatternGenerator() { } KoPatternGenerator::KoPatternGenerator() : KisGenerator(id(), KoID("basic"), i18n("&Pattern...")) { setColorSpaceIndependence(FULLY_INDEPENDENT); setSupportsPainting(true); } KisFilterConfigurationSP KoPatternGenerator::factoryConfiguration() const { KisFilterConfigurationSP config = new KisFilterConfiguration("pattern", 1); QVariant v; v.setValue(QString("Grid01.pat")); config->setProperty("pattern", v); // v.setValue(KoColor()); // config->setProperty("color", v); return config; } KisConfigWidget * KoPatternGenerator::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const { Q_UNUSED(dev); return new KisWdgPattern(parent); } void KoPatternGenerator::generate(KisProcessingInformation dstInfo, const QSize& size, const KisFilterConfigurationSP config, KoUpdater* progressUpdater) const { KisPaintDeviceSP dst = dstInfo.paintDevice(); Q_ASSERT(!dst.isNull()); Q_ASSERT(config); if (!config) return; QString patternName = config->getString("pattern", "Grid01.pat"); KoResourceServer *rserver = KoResourceServerProvider::instance()->patternServer(); - KoPattern *pattern = rserver->resourceByName(patternName); + KoPatternSP pattern = rserver->resourceByName(patternName); // KoColor c = config->getColor("color"); KisFillPainter gc(dst); gc.setPattern(pattern); // gc.setPaintColor(c); gc.setProgress(progressUpdater); gc.setChannelFlags(config->channelFlags()); gc.setOpacity(OPACITY_OPAQUE_U8); gc.setSelection(dstInfo.selection()); gc.setWidth(size.width()); gc.setHeight(size.height()); gc.setFillStyle(KisFillPainter::FillStylePattern); gc.fillRect(QRect(dstInfo.topLeft(), size), pattern); gc.end(); } #include "patterngenerator.moc" diff --git a/plugins/impex/brush/kis_brush_import.cpp b/plugins/impex/brush/kis_brush_import.cpp index fb681bf25e..3eb036712b 100644 --- a/plugins/impex/brush/kis_brush_import.cpp +++ b/plugins/impex/brush/kis_brush_import.cpp @@ -1,123 +1,120 @@ /* * Copyright (c) 2016 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_brush_import.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KisBrushImportFactory, "krita_brush_import.json", registerPlugin();) KisBrushImport::KisBrushImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } KisBrushImport::~KisBrushImport() { } KisImportExportFilter::ConversionStatus KisBrushImport::convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP /*configuration*/) { - KisBrush *brush; + KisBrushSP brush; if (mimeType() == "image/x-gimp-brush") { - brush = new KisGbrBrush(filename()); + brush = KisBrushSP(new KisGbrBrush(filename())); } else if (mimeType() == "image/x-gimp-brush-animated") { - brush = new KisImagePipeBrush(filename()); + brush = KisBrushSP(new KisImagePipeBrush(filename())); } else { return KisImportExportFilter::BadMimeType; } if (!brush->loadFromDevice(io)) { - delete brush; return KisImportExportFilter::InvalidFormat; } if (!brush->valid()) { - delete brush; return KisImportExportFilter::InvalidFormat; } const KoColorSpace *colorSpace = 0; if (brush->hasColor()) { colorSpace = KoColorSpaceRegistry::instance()->rgb8(); } else { colorSpace = KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer8BitsColorDepthID.id(), ""); } KisImageSP image = new KisImage(document->createUndoStore(), brush->width(), brush->height(), colorSpace, brush->name()); image->setProperty("brushspacing", brush->spacing()); - KisImagePipeBrush *pipeBrush = dynamic_cast(brush); + KisImagePipeBrushSP pipeBrush = brush.dynamicCast(); if (pipeBrush) { - QVector brushes = pipeBrush->brushes(); + QVector brushes = pipeBrush->brushes(); for(int i = brushes.size(); i > 0; i--) { - KisGbrBrush *subbrush = brushes.at(i - 1); + KisGbrBrushSP subbrush = brushes.at(i - 1); const KoColorSpace *subColorSpace = 0; if (brush->hasColor()) { subColorSpace = KoColorSpaceRegistry::instance()->rgb8(); } else { subColorSpace = KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer8BitsColorDepthID.id(), ""); } KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), 255, subColorSpace); layer->paintDevice()->convertFromQImage(subbrush->brushTipImage(), 0, 0, 0); image->addNode(layer, image->rootLayer()); } KisAnnotationSP ann = new KisAnimatedBrushAnnotation(pipeBrush->parasite()); image->addAnnotation(ann); } else { KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), 255, colorSpace); layer->paintDevice()->convertFromQImage(brush->brushTipImage(), 0, 0, 0); image->addNode(layer, image->rootLayer(), 0); } document->setCurrentImage(image); - delete brush; return KisImportExportFilter::OK; } #include "kis_brush_import.moc" diff --git a/plugins/impex/libkra/kis_kra_loader.cpp b/plugins/impex/libkra/kis_kra_loader.cpp index 514eff3c7a..afa41865f0 100644 --- a/plugins/impex/libkra/kis_kra_loader.cpp +++ b/plugins/impex/libkra/kis_kra_loader.cpp @@ -1,1247 +1,1245 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2007 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_kra_loader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lazybrush/kis_colorize_mask.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisResourceServerProvider.h" #include "kis_keyframe_channel.h" #include #include "KisReferenceImagesLayer.h" #include "KisReferenceImage.h" #include #include "KisDocument.h" #include "kis_config.h" #include "kis_kra_tags.h" #include "kis_kra_utils.h" #include "kis_kra_load_visitor.h" #include "kis_dom_utils.h" #include "kis_image_animation_interface.h" #include "kis_time_range.h" #include "kis_grid_config.h" #include "kis_guides_config.h" #include "kis_image_config.h" #include "KisProofingConfiguration.h" #include "kis_layer_properties_icons.h" #include "kis_node_view_color_scheme.h" /* Color model id comparison through the ages: 2.4 2.5 2.6 ideal ALPHA ALPHA ALPHA ALPHAU8 CMYK CMYK CMYK CMYKAU8 CMYKAF32 CMYKAF32 CMYKA16 CMYKAU16 CMYKAU16 GRAYA GRAYA GRAYA GRAYAU8 GrayF32 GRAYAF32 GRAYAF32 GRAYA16 GRAYAU16 GRAYAU16 LABA LABA LABA LABAU16 LABAF32 LABAF32 LABAU8 LABAU8 RGBA RGBA RGBA RGBAU8 RGBA16 RGBA16 RGBA16 RGBAU16 RgbAF32 RGBAF32 RGBAF32 RgbAF16 RgbAF16 RGBAF16 XYZA16 XYZA16 XYZA16 XYZAU16 XYZA8 XYZA8 XYZAU8 XyzAF16 XyzAF16 XYZAF16 XyzAF32 XYZAF32 XYZAF32 YCbCrA YCBCRA8 YCBCRA8 YCBCRAU8 YCbCrAU16 YCBCRAU16 YCBCRAU16 YCBCRF32 YCBCRF32 */ using namespace KRA; struct KisKraLoader::Private { public: KisDocument* document; QString imageName; // used to be stored in the image, is now in the documentInfo block QString imageComment; // used to be stored in the image, is now in the documentInfo block QMap layerFilenames; // temp storage during loading int syntaxVersion; // version of the fileformat we are loading vKisNodeSP selectedNodes; // the nodes that were active when saving the document. QMap assistantsFilenames; QList assistants; QMap keyframeFilenames; QVector paletteFilenames; QStringList errorMessages; QStringList warningMessages; }; void convertColorSpaceNames(QString &colorspacename, QString &profileProductName) { if (colorspacename == "Grayscale + Alpha") { colorspacename = "GRAYA"; profileProductName.clear(); } else if (colorspacename == "RgbAF32") { colorspacename = "RGBAF32"; profileProductName.clear(); } else if (colorspacename == "RgbAF16") { colorspacename = "RGBAF16"; profileProductName.clear(); } else if (colorspacename == "CMYKA16") { colorspacename = "CMYKAU16"; } else if (colorspacename == "GrayF32") { colorspacename = "GRAYAF32"; profileProductName.clear(); } else if (colorspacename == "GRAYA16") { colorspacename = "GRAYAU16"; } else if (colorspacename == "XyzAF16") { colorspacename = "XYZAF16"; profileProductName.clear(); } else if (colorspacename == "XyzAF32") { colorspacename = "XYZAF32"; profileProductName.clear(); } else if (colorspacename == "YCbCrA") { colorspacename = "YCBCRA8"; } else if (colorspacename == "YCbCrAU16") { colorspacename = "YCBCRAU16"; } } KisKraLoader::KisKraLoader(KisDocument * document, int syntaxVersion) : m_d(new Private()) { m_d->document = document; m_d->syntaxVersion = syntaxVersion; } KisKraLoader::~KisKraLoader() { delete m_d; } KisImageSP KisKraLoader::loadXML(const KoXmlElement& element) { QString attr; KisImageSP image = 0; QString name; qint32 width; qint32 height; QString profileProductName; double xres; double yres; QString colorspacename; const KoColorSpace * cs; if ((attr = element.attribute(MIME)) == NATIVE_MIMETYPE) { if ((m_d->imageName = element.attribute(NAME)).isNull()) { m_d->errorMessages << i18n("Image does not have a name."); return KisImageSP(0); } if ((attr = element.attribute(WIDTH)).isNull()) { m_d->errorMessages << i18n("Image does not specify a width."); return KisImageSP(0); } width = KisDomUtils::toInt(attr); if ((attr = element.attribute(HEIGHT)).isNull()) { m_d->errorMessages << i18n("Image does not specify a height."); return KisImageSP(0); } height = KisDomUtils::toInt(attr); m_d->imageComment = element.attribute(DESCRIPTION); xres = 100.0 / 72.0; if (!(attr = element.attribute(X_RESOLUTION)).isNull()) { qreal value = KisDomUtils::toDouble(attr); if (value > 1.0) { xres = value / 72.0; } } yres = 100.0 / 72.0; if (!(attr = element.attribute(Y_RESOLUTION)).isNull()) { qreal value = KisDomUtils::toDouble(attr); if (value > 1.0) { yres = value / 72.0; } } if ((colorspacename = element.attribute(COLORSPACE_NAME)).isNull()) { // An old file: take a reasonable default. // Krita didn't support anything else in those // days anyway. colorspacename = "RGBA"; } profileProductName = element.attribute(PROFILE); // A hack for an old colorspacename convertColorSpaceNames(colorspacename, profileProductName); QString colorspaceModel = KoColorSpaceRegistry::instance()->colorSpaceColorModelId(colorspacename).id(); QString colorspaceDepth = KoColorSpaceRegistry::instance()->colorSpaceColorDepthId(colorspacename).id(); if (profileProductName.isNull()) { // no mention of profile so get default profile"; cs = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, ""); } else { cs = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, profileProductName); } if (cs == 0) { // try once more without the profile cs = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, ""); if (cs == 0) { m_d->errorMessages << i18n("Image specifies an unsupported color model: %1.", colorspacename); return KisImageSP(0); } } KisProofingConfigurationSP proofingConfig = KisImageConfig(true).defaultProofingconfiguration(); if (!(attr = element.attribute(PROOFINGPROFILENAME)).isNull()) { proofingConfig->proofingProfile = attr; } if (!(attr = element.attribute(PROOFINGMODEL)).isNull()) { proofingConfig->proofingModel = attr; } if (!(attr = element.attribute(PROOFINGDEPTH)).isNull()) { proofingConfig->proofingDepth = attr; } if (!(attr = element.attribute(PROOFINGINTENT)).isNull()) { proofingConfig->intent = (KoColorConversionTransformation::Intent) KisDomUtils::toInt(attr); } if (!(attr = element.attribute(PROOFINGADAPTATIONSTATE)).isNull()) { proofingConfig->adaptationState = KisDomUtils::toDouble(attr); } if (m_d->document) { image = new KisImage(m_d->document->createUndoStore(), width, height, cs, name); } else { image = new KisImage(0, width, height, cs, name); } image->setResolution(xres, yres); loadNodes(element, image, const_cast(image->rootLayer().data())); KoXmlNode child; for (child = element.lastChild(); !child.isNull(); child = child.previousSibling()) { KoXmlElement e = child.toElement(); if(e.tagName() == CANVASPROJECTIONCOLOR) { if (e.hasAttribute(COLORBYTEDATA)) { QByteArray colorData = QByteArray::fromBase64(e.attribute(COLORBYTEDATA).toLatin1()); KoColor color((const quint8*)colorData.data(), image->colorSpace()); image->setDefaultProjectionColor(color); } } if(e.tagName() == GLOBALASSISTANTSCOLOR) { if (e.hasAttribute(SIMPLECOLORDATA)) { QString colorData = e.attribute(SIMPLECOLORDATA); m_d->document->setAssistantsGlobalColor(KisDomUtils::qStringToQColor(colorData)); } } if(e.tagName()== PROOFINGWARNINGCOLOR) { QDomDocument dom; KoXml::asQDomElement(dom, e); QDomElement eq = dom.firstChildElement(); proofingConfig->warningColor = KoColor::fromXML(eq.firstChildElement(), Integer8BitsColorDepthID.id()); } if (e.tagName().toLower() == "animation") { loadAnimationMetadata(e, image); } } image->setProofingConfiguration(proofingConfig); for (child = element.lastChild(); !child.isNull(); child = child.previousSibling()) { KoXmlElement e = child.toElement(); if(e.tagName() == "compositions") { loadCompositions(e, image); } } } KoXmlNode child; for (child = element.lastChild(); !child.isNull(); child = child.previousSibling()) { KoXmlElement e = child.toElement(); if (e.tagName() == "grid") { loadGrid(e); } else if (e.tagName() == "guides") { loadGuides(e); } else if (e.tagName() == "assistants") { loadAssistantsList(e); } else if (e.tagName() == "audio") { loadAudio(e, image); } } // reading palettes from XML for (child = element.lastChild(); !child.isNull(); child = child.previousSibling()) { QDomElement e = child.toElement(); if (e.tagName() == PALETTES) { for (QDomElement paletteElement = e.lastChildElement(); !paletteElement.isNull(); paletteElement = paletteElement.previousSiblingElement()) { QString paletteName = paletteElement.attribute("filename"); m_d->paletteFilenames.append(paletteName); } break; } } return image; } void KisKraLoader::loadBinaryData(KoStore * store, KisImageSP image, const QString & uri, bool external) { // icc profile: if present, this overrides the profile product name loaded in loadXML. QString location = external ? QString() : uri; location += m_d->imageName + ICC_PATH; if (store->hasFile(location)) { if (store->open(location)) { QByteArray data; data.resize(store->size()); bool res = (store->read(data.data(), store->size()) > -1); store->close(); if (res) { const KoColorProfile *profile = KoColorSpaceRegistry::instance()->createColorProfile(image->colorSpace()->colorModelId().id(), image->colorSpace()->colorDepthId().id(), data); if (profile && profile->valid()) { res = image->assignImageProfile(profile); } if (!res) { const QString defaultProfileId = KoColorSpaceRegistry::instance()->defaultProfileForColorSpace(image->colorSpace()->id()); profile = KoColorSpaceRegistry::instance()->profileByName(defaultProfileId); Q_ASSERT(profile && profile->valid()); image->assignImageProfile(profile); } } } } //load the embed proofing profile, it only needs to be loaded into Krita, not assigned. location = external ? QString() : uri; location += m_d->imageName + ICC_PROOFING_PATH; if (store->hasFile(location)) { if (store->open(location)) { QByteArray proofingData; proofingData.resize(store->size()); bool proofingProfileRes = (store->read(proofingData.data(), store->size())>-1); store->close(); KisProofingConfigurationSP proofingConfig = image->proofingConfiguration(); if (!proofingConfig) { proofingConfig = KisImageConfig(true).defaultProofingconfiguration(); } if (proofingProfileRes) { const KoColorProfile *proofingProfile = KoColorSpaceRegistry::instance()->createColorProfile(proofingConfig->proofingModel, proofingConfig->proofingDepth, proofingData); if (proofingProfile->valid()){ KoColorSpaceRegistry::instance()->addProfile(proofingProfile); } } } } // Load the layers data: if there is a profile associated with a layer it will be set now. KisKraLoadVisitor visitor(image, store, m_d->document->shapeController(), m_d->layerFilenames, m_d->keyframeFilenames, m_d->imageName, m_d->syntaxVersion); if (external) { visitor.setExternalUri(uri); } image->rootLayer()->accept(visitor); if (!visitor.errorMessages().isEmpty()) { m_d->errorMessages.append(visitor.errorMessages()); } if (!visitor.warningMessages().isEmpty()) { m_d->warningMessages.append(visitor.warningMessages()); } // annotations // exif location = external ? QString() : uri; location += m_d->imageName + EXIF_PATH; if (store->hasFile(location)) { QByteArray data; store->open(location); data = store->read(store->size()); store->close(); image->addAnnotation(KisAnnotationSP(new KisAnnotation("exif", "", data))); } // layer styles location = external ? QString() : uri; location += m_d->imageName + LAYER_STYLES_PATH; if (store->hasFile(location)) { - KisPSDLayerStyleCollectionResource *collection = - new KisPSDLayerStyleCollectionResource("Embedded Styles.asl"); + KisPSDLayerStyleCollectionResourceSP collection(new KisPSDLayerStyleCollectionResource("Embedded Styles.asl")); collection->setName(i18nc("Auto-generated layer style collection name for embedded styles (collection)", "<%1> (embedded)", m_d->imageName)); KIS_ASSERT_RECOVER_NOOP(!collection->valid()); store->open(location); { KoStoreDevice device(store); device.open(QIODevice::ReadOnly); /** * ASL loading code cannot work with non-sequential IO devices, * so convert the device beforehand! */ QByteArray buf = device.readAll(); QBuffer raDevice(&buf); raDevice.open(QIODevice::ReadOnly); collection->loadFromDevice(&raDevice); } store->close(); if (collection->valid()) { KoResourceServer *server = KisResourceServerProvider::instance()->layerStyleCollectionServer(); server->addResource(collection, false); collection->assignAllLayerStyles(image->root()); } else { warnKrita << "WARNING: Couldn't load layer styles library from .kra!"; - delete collection; } } if (m_d->document && m_d->document->documentInfo()->aboutInfo("title").isNull()) m_d->document->documentInfo()->setAboutInfo("title", m_d->imageName); if (m_d->document && m_d->document->documentInfo()->aboutInfo("comment").isNull()) m_d->document->documentInfo()->setAboutInfo("comment", m_d->imageComment); loadAssistants(store, uri, external); } void KisKraLoader::loadPalettes(KoStore *store, KisDocument *doc) { - QList list; + QList list; Q_FOREACH (const QString &filename, m_d->paletteFilenames) { - KoColorSet *newPalette = new KoColorSet(filename); + KoColorSetSP newPalette(new KoColorSet(filename)); store->open(m_d->imageName + PALETTE_PATH + filename); QByteArray data = store->read(store->size()); newPalette->fromByteArray(data); newPalette->setIsGlobal(false); newPalette->setIsEditable(true); store->close(); list.append(newPalette); } doc->setPaletteList(list); } vKisNodeSP KisKraLoader::selectedNodes() const { return m_d->selectedNodes; } QList KisKraLoader::assistants() const { return m_d->assistants; } QStringList KisKraLoader::errorMessages() const { return m_d->errorMessages; } QStringList KisKraLoader::warningMessages() const { return m_d->warningMessages; } void KisKraLoader::loadAssistants(KoStore *store, const QString &uri, bool external) { QString file_path; QString location; QMap handleMap; KisPaintingAssistant* assistant = 0; const QColor globalColor = m_d->document->assistantsGlobalColor(); QMap::const_iterator loadedAssistant = m_d->assistantsFilenames.constBegin(); while (loadedAssistant != m_d->assistantsFilenames.constEnd()){ const KisPaintingAssistantFactory* factory = KisPaintingAssistantFactoryRegistry::instance()->get(loadedAssistant.value()); if (factory) { assistant = factory->createPaintingAssistant(); location = external ? QString() : uri; location += m_d->imageName + ASSISTANTS_PATH; file_path = location + loadedAssistant.key(); assistant->loadXml(store, handleMap, file_path); assistant->setAssistantGlobalColorCache(globalColor); //If an assistant has too few handles than it should according to it's own setup, just don't load it// if (assistant->handles().size()==assistant->numHandles()){ m_d->assistants.append(toQShared(assistant)); } } loadedAssistant++; } } void KisKraLoader::loadAnimationMetadata(const KoXmlElement &element, KisImageSP image) { QDomDocument qDom; KoXml::asQDomElement(qDom, element); QDomElement qElement = qDom.firstChildElement(); float framerate; KisTimeRange range; int currentTime; KisImageAnimationInterface *animation = image->animationInterface(); if (KisDomUtils::loadValue(qElement, "framerate", &framerate)) { animation->setFramerate(framerate); } if (KisDomUtils::loadValue(qElement, "range", &range)) { animation->setFullClipRange(range); } if (KisDomUtils::loadValue(qElement, "currentTime", ¤tTime)) { animation->switchCurrentTimeAsync(currentTime); } } KisNodeSP KisKraLoader::loadNodes(const KoXmlElement& element, KisImageSP image, KisNodeSP parent) { KoXmlNode node = element.firstChild(); KoXmlNode child; if (!node.isNull()) { if (node.isElement()) { if (node.nodeName().toUpper() == LAYERS.toUpper() || node.nodeName().toUpper() == MASKS.toUpper()) { for (child = node.lastChild(); !child.isNull(); child = child.previousSibling()) { KisNodeSP node = loadNode(child.toElement(), image); if (node) { image->nextLayerName(); // Make sure the nameserver is current with the number of nodes. image->addNode(node, parent); if (node->inherits("KisLayer") && KoXml::childNodesCount(child) > 0) { loadNodes(child.toElement(), image, node); } } } } } } return parent; } KisNodeSP KisKraLoader::loadNode(const KoXmlElement& element, KisImageSP image) { // Nota bene: If you add new properties to layers, you should // ALWAYS define a default value in case the property is not // present in the layer definition: this helps a LOT with backward // compatibility. QString name = element.attribute(NAME, "No Name"); QUuid id = QUuid(element.attribute(UUID, QUuid().toString())); qint32 x = element.attribute(X, "0").toInt(); qint32 y = element.attribute(Y, "0").toInt(); qint32 opacity = element.attribute(OPACITY, QString::number(OPACITY_OPAQUE_U8)).toInt(); if (opacity < OPACITY_TRANSPARENT_U8) opacity = OPACITY_TRANSPARENT_U8; if (opacity > OPACITY_OPAQUE_U8) opacity = OPACITY_OPAQUE_U8; const KoColorSpace* colorSpace = 0; if ((element.attribute(COLORSPACE_NAME)).isNull()) { dbgFile << "No attribute color space for layer: " << name; colorSpace = image->colorSpace(); } else { QString colorspacename = element.attribute(COLORSPACE_NAME); QString profileProductName; convertColorSpaceNames(colorspacename, profileProductName); QString colorspaceModel = KoColorSpaceRegistry::instance()->colorSpaceColorModelId(colorspacename).id(); QString colorspaceDepth = KoColorSpaceRegistry::instance()->colorSpaceColorDepthId(colorspacename).id(); dbgFile << "Searching color space: " << colorspacename << colorspaceModel << colorspaceDepth << " for layer: " << name; // use default profile - it will be replaced later in completeLoading colorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorspaceModel, colorspaceDepth, ""); dbgFile << "found colorspace" << colorSpace; if (!colorSpace) { m_d->warningMessages << i18n("Layer %1 specifies an unsupported color model: %2.", name, colorspacename); return 0; } } const bool visible = element.attribute(VISIBLE, "1") == "0" ? false : true; const bool locked = element.attribute(LOCKED, "0") == "0" ? false : true; const bool collapsed = element.attribute(COLLAPSED, "0") == "0" ? false : true; int colorLabelIndex = element.attribute(COLOR_LABEL, "0").toInt(); QVector labels = KisNodeViewColorScheme::instance()->allColorLabels(); if (colorLabelIndex >= labels.size()) { colorLabelIndex = labels.size() - 1; } // Now find out the layer type and do specific handling QString nodeType; if (m_d->syntaxVersion == 1) { nodeType = element.attribute("layertype"); if (nodeType.isEmpty()) { nodeType = PAINT_LAYER; } } else { nodeType = element.attribute(NODE_TYPE); } if (nodeType.isEmpty()) { m_d->warningMessages << i18n("Layer %1 has an unsupported type.", name); return 0; } KisNodeSP node = 0; if (nodeType == PAINT_LAYER) node = loadPaintLayer(element, image, name, colorSpace, opacity); else if (nodeType == GROUP_LAYER) node = loadGroupLayer(element, image, name, colorSpace, opacity); else if (nodeType == ADJUSTMENT_LAYER) node = loadAdjustmentLayer(element, image, name, colorSpace, opacity); else if (nodeType == SHAPE_LAYER) node = loadShapeLayer(element, image, name, colorSpace, opacity); else if (nodeType == GENERATOR_LAYER) node = loadGeneratorLayer(element, image, name, colorSpace, opacity); else if (nodeType == CLONE_LAYER) node = loadCloneLayer(element, image, name, colorSpace, opacity); else if (nodeType == FILTER_MASK) node = loadFilterMask(element); else if (nodeType == TRANSFORM_MASK) node = loadTransformMask(element); else if (nodeType == TRANSPARENCY_MASK) node = loadTransparencyMask(element); else if (nodeType == SELECTION_MASK) node = loadSelectionMask(image, element); else if (nodeType == COLORIZE_MASK) node = loadColorizeMask(image, element, colorSpace); else if (nodeType == FILE_LAYER) node = loadFileLayer(element, image, name, opacity); else if (nodeType == REFERENCE_IMAGES_LAYER) node = loadReferenceImagesLayer(element, image); else { m_d->warningMessages << i18n("Layer %1 has an unsupported type: %2.", name, nodeType); return 0; } // Loading the node went wrong. Return empty node and leave to // upstream to complain to the user if (!node) { m_d->warningMessages << i18n("Failure loading layer %1 of type: %2.", name, nodeType); return 0; } node->setVisible(visible, true); node->setUserLocked(locked); node->setCollapsed(collapsed); node->setColorLabelIndex(colorLabelIndex); node->setX(x); node->setY(y); node->setName(name); if (! id.isNull()) // if no uuid in file, new one has been generated already node->setUuid(id); if (node->inherits("KisLayer") || node->inherits("KisColorizeMask")) { QString compositeOpName = element.attribute(COMPOSITE_OP, "normal"); node->setCompositeOpId(compositeOpName); } if (node->inherits("KisLayer")) { KisLayer* layer = qobject_cast(node.data()); QBitArray channelFlags = stringToFlags(element.attribute(CHANNEL_FLAGS, ""), colorSpace->channelCount()); layer->setChannelFlags(channelFlags); if (element.hasAttribute(LAYER_STYLE_UUID)) { QString uuidString = element.attribute(LAYER_STYLE_UUID); QUuid uuid(uuidString); if (!uuid.isNull()) { KisPSDLayerStyleSP dumbLayerStyle(new KisPSDLayerStyle()); dumbLayerStyle->setUuid(uuid); layer->setLayerStyle(dumbLayerStyle); } else { warnKrita << "WARNING: Layer style for layer" << layer->name() << "contains invalid UUID" << uuidString; } } } if (node->inherits("KisGroupLayer")) { if (element.hasAttribute(PASS_THROUGH_MODE)) { bool value = element.attribute(PASS_THROUGH_MODE, "0") != "0"; KisGroupLayer *group = qobject_cast(node.data()); group->setPassThroughMode(value); } } const bool timelineEnabled = element.attribute(VISIBLE_IN_TIMELINE, "0") == "0" ? false : true; node->setUseInTimeline(timelineEnabled); if (node->inherits("KisPaintLayer")) { KisPaintLayer* layer = qobject_cast(node.data()); QBitArray channelLockFlags = stringToFlags(element.attribute(CHANNEL_LOCK_FLAGS, ""), colorSpace->channelCount()); layer->setChannelLockFlags(channelLockFlags); bool onionEnabled = element.attribute(ONION_SKIN_ENABLED, "0") == "0" ? false : true; layer->setOnionSkinEnabled(onionEnabled); } if (element.attribute(FILE_NAME).isNull()) { m_d->layerFilenames[node.data()] = name; } else { m_d->layerFilenames[node.data()] = element.attribute(FILE_NAME); } if (element.hasAttribute("selected") && element.attribute("selected") == "true") { m_d->selectedNodes.append(node); } if (element.hasAttribute(KEYFRAME_FILE)) { m_d->keyframeFilenames.insert(node.data(), element.attribute(KEYFRAME_FILE)); } return node; } KisNodeSP KisKraLoader::loadPaintLayer(const KoXmlElement& element, KisImageSP image, const QString& name, const KoColorSpace* cs, quint32 opacity) { Q_UNUSED(element); KisPaintLayer* layer; layer = new KisPaintLayer(image, name, opacity, cs); Q_CHECK_PTR(layer); return layer; } KisNodeSP KisKraLoader::loadFileLayer(const KoXmlElement& element, KisImageSP image, const QString& name, quint32 opacity) { QString filename = element.attribute("source", QString()); if (filename.isNull()) return 0; bool scale = (element.attribute("scale", "true") == "true"); int scalingMethod = element.attribute("scalingmethod", "-1").toInt(); if (scalingMethod < 0) { if (scale) { scalingMethod = KisFileLayer::ToImagePPI; } else { scalingMethod = KisFileLayer::None; } } QString documentPath; if (m_d->document) { documentPath = m_d->document->url().toLocalFile(); } QFileInfo info(documentPath); QString basePath = info.absolutePath(); QString fullPath = QDir(basePath).filePath(QDir::cleanPath(filename)); if (!QFileInfo(fullPath).exists()) { qApp->setOverrideCursor(Qt::ArrowCursor); QString msg = i18nc( "@info", "The file associated to a file layer with the name \"%1\" is not found.\n\n" "Expected path:\n" "%2\n\n" "Do you want to locate it manually?", name, fullPath); int result = QMessageBox::warning(0, i18nc("@title:window", "File not found"), msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); if (result == QMessageBox::Yes) { KoFileDialog dialog(0, KoFileDialog::OpenFile, "OpenDocument"); dialog.setMimeTypeFilters(KisImportExportManager::supportedMimeTypes(KisImportExportManager::Import)); dialog.setDefaultDir(basePath); QString url = dialog.filename(); if (!QFileInfo(basePath).exists()) { filename = url; } else { QDir d(basePath); filename = d.relativeFilePath(url); } } qApp->restoreOverrideCursor(); } KisLayer *layer = new KisFileLayer(image, basePath, filename, (KisFileLayer::ScalingMethod)scalingMethod, name, opacity); Q_CHECK_PTR(layer); return layer; } KisNodeSP KisKraLoader::loadGroupLayer(const KoXmlElement& element, KisImageSP image, const QString& name, const KoColorSpace* cs, quint32 opacity) { Q_UNUSED(element); Q_UNUSED(cs); QString attr; KisGroupLayer* layer; layer = new KisGroupLayer(image, name, opacity); Q_CHECK_PTR(layer); return layer; } KisNodeSP KisKraLoader::loadAdjustmentLayer(const KoXmlElement& element, KisImageSP image, const QString& name, const KoColorSpace* cs, quint32 opacity) { // XXX: do something with filterversion? Q_UNUSED(cs); QString attr; KisAdjustmentLayer* layer; QString filtername; QString legacy = filtername; if ((filtername = element.attribute(FILTER_NAME)).isNull()) { // XXX: Invalid adjustmentlayer! We should warn about it! warnFile << "No filter in adjustment layer"; return 0; } //get deprecated filters. if (filtername=="brightnesscontrast") { legacy = filtername; filtername = "perchannel"; } if (filtername=="left edge detections" || filtername=="right edge detections" || filtername=="top edge detections" || filtername=="bottom edge detections") { legacy = filtername; filtername = "edge detection"; } KisFilterSP f = KisFilterRegistry::instance()->value(filtername); if (!f) { warnFile << "No filter for filtername" << filtername << ""; return 0; // XXX: We don't have this filter. We should warn about it! } KisFilterConfigurationSP kfc = f->defaultConfiguration(); kfc->setProperty("legacy", legacy); if (legacy=="brightnesscontrast") { kfc->setProperty("colorModel", cs->colorModelId().id()); } // We'll load the configuration and the selection later. layer = new KisAdjustmentLayer(image, name, kfc, 0); Q_CHECK_PTR(layer); layer->setOpacity(opacity); return layer; } KisNodeSP KisKraLoader::loadShapeLayer(const KoXmlElement& element, KisImageSP image, const QString& name, const KoColorSpace* cs, quint32 opacity) { Q_UNUSED(element); Q_UNUSED(cs); QString attr; KoShapeControllerBase * shapeController = 0; if (m_d->document) { shapeController = m_d->document->shapeController(); } KisShapeLayer* layer = new KisShapeLayer(shapeController, image, name, opacity); Q_CHECK_PTR(layer); return layer; } KisNodeSP KisKraLoader::loadGeneratorLayer(const KoXmlElement& element, KisImageSP image, const QString& name, const KoColorSpace* cs, quint32 opacity) { Q_UNUSED(cs); // XXX: do something with generator version? KisGeneratorLayer* layer; QString generatorname = element.attribute(GENERATOR_NAME); if (generatorname.isNull()) { // XXX: Invalid generator layer! We should warn about it! warnFile << "No generator in generator layer"; return 0; } KisGeneratorSP generator = KisGeneratorRegistry::instance()->value(generatorname); if (!generator) { warnFile << "No generator for generatorname" << generatorname << ""; return 0; // XXX: We don't have this generator. We should warn about it! } KisFilterConfigurationSP kgc = generator->defaultConfiguration(); // We'll load the configuration and the selection later. layer = new KisGeneratorLayer(image, name, kgc, 0); Q_CHECK_PTR(layer); layer->setOpacity(opacity); return layer; } KisNodeSP KisKraLoader::loadCloneLayer(const KoXmlElement& element, KisImageSP image, const QString& name, const KoColorSpace* cs, quint32 opacity) { Q_UNUSED(cs); KisCloneLayerSP layer = new KisCloneLayer(0, image, name, opacity); KisNodeUuidInfo info; if (! (element.attribute(CLONE_FROM_UUID)).isNull()) { info = KisNodeUuidInfo(QUuid(element.attribute(CLONE_FROM_UUID))); } else { if ((element.attribute(CLONE_FROM)).isNull()) { return 0; } else { info = KisNodeUuidInfo(element.attribute(CLONE_FROM)); } } layer->setCopyFromInfo(info); if ((element.attribute(CLONE_TYPE)).isNull()) { return 0; } else { layer->setCopyType((CopyLayerType) element.attribute(CLONE_TYPE).toInt()); } return layer; } KisNodeSP KisKraLoader::loadFilterMask(const KoXmlElement& element) { QString attr; KisFilterMask* mask; QString filtername; // XXX: should we check the version? if ((filtername = element.attribute(FILTER_NAME)).isNull()) { // XXX: Invalid filter layer! We should warn about it! warnFile << "No filter in filter layer"; return 0; } KisFilterSP f = KisFilterRegistry::instance()->value(filtername); if (!f) { warnFile << "No filter for filtername" << filtername << ""; return 0; // XXX: We don't have this filter. We should warn about it! } KisFilterConfigurationSP kfc = f->defaultConfiguration(); // We'll load the configuration and the selection later. mask = new KisFilterMask(); mask->setFilter(kfc); Q_CHECK_PTR(mask); return mask; } KisNodeSP KisKraLoader::loadTransformMask(const KoXmlElement& element) { Q_UNUSED(element); KisTransformMask* mask; /** * We'll load the transform configuration later on a stage * of binary data loading */ mask = new KisTransformMask(); Q_CHECK_PTR(mask); return mask; } KisNodeSP KisKraLoader::loadTransparencyMask(const KoXmlElement& element) { Q_UNUSED(element); KisTransparencyMask* mask = new KisTransparencyMask(); Q_CHECK_PTR(mask); return mask; } KisNodeSP KisKraLoader::loadSelectionMask(KisImageSP image, const KoXmlElement& element) { KisSelectionMaskSP mask = new KisSelectionMask(image); bool active = element.attribute(ACTIVE, "1") == "0" ? false : true; mask->setActive(active); Q_CHECK_PTR(mask); return mask; } KisNodeSP KisKraLoader::loadColorizeMask(KisImageSP image, const KoXmlElement& element, const KoColorSpace *colorSpace) { KisColorizeMaskSP mask = new KisColorizeMask(); const bool editKeystrokes = element.attribute(COLORIZE_EDIT_KEYSTROKES, "1") == "0" ? false : true; const bool showColoring = element.attribute(COLORIZE_SHOW_COLORING, "1") == "0" ? false : true; KisLayerPropertiesIcons::setNodeProperty(mask, KisLayerPropertiesIcons::colorizeEditKeyStrokes, editKeystrokes, image); KisLayerPropertiesIcons::setNodeProperty(mask, KisLayerPropertiesIcons::colorizeShowColoring, showColoring, image); const bool useEdgeDetection = KisDomUtils::toInt(element.attribute(COLORIZE_USE_EDGE_DETECTION, "0")); const qreal edgeDetectionSize = KisDomUtils::toDouble(element.attribute(COLORIZE_EDGE_DETECTION_SIZE, "4")); const qreal radius = KisDomUtils::toDouble(element.attribute(COLORIZE_FUZZY_RADIUS, "0")); const int cleanUp = KisDomUtils::toInt(element.attribute(COLORIZE_CLEANUP, "0")); const bool limitToDevice = KisDomUtils::toInt(element.attribute(COLORIZE_LIMIT_TO_DEVICE, "0")); mask->setUseEdgeDetection(useEdgeDetection); mask->setEdgeDetectionSize(edgeDetectionSize); mask->setFuzzyRadius(radius); mask->setCleanUpAmount(qreal(cleanUp) / 100.0); mask->setLimitToDeviceBounds(limitToDevice); delete mask->setColorSpace(colorSpace); mask->setImage(image); return mask; } void KisKraLoader::loadCompositions(const KoXmlElement& elem, KisImageSP image) { KoXmlNode child; for (child = elem.firstChild(); !child.isNull(); child = child.nextSibling()) { KoXmlElement e = child.toElement(); QString name = e.attribute("name"); bool exportEnabled = e.attribute("exportEnabled", "1") == "0" ? false : true; KisLayerCompositionSP composition(new KisLayerComposition(image, name)); composition->setExportEnabled(exportEnabled); KoXmlNode value; for (value = child.lastChild(); !value.isNull(); value = value.previousSibling()) { KoXmlElement e = value.toElement(); QUuid uuid(e.attribute("uuid")); bool visible = e.attribute("visible", "1") == "0" ? false : true; composition->setVisible(uuid, visible); bool collapsed = e.attribute("collapsed", "1") == "0" ? false : true; composition->setCollapsed(uuid, collapsed); } image->addComposition(composition); } } void KisKraLoader::loadAssistantsList(const KoXmlElement &elem) { KoXmlNode child; int count = 0; for (child = elem.firstChild(); !child.isNull(); child = child.nextSibling()) { KoXmlElement e = child.toElement(); QString type = e.attribute("type"); QString file_name = e.attribute("filename"); m_d->assistantsFilenames.insert(file_name,type); count++; } } void KisKraLoader::loadGrid(const KoXmlElement& elem) { QDomDocument dom; KoXml::asQDomElement(dom, elem); QDomElement domElement = dom.firstChildElement(); KisGridConfig config; config.loadDynamicDataFromXml(domElement); config.loadStaticData(); m_d->document->setGridConfig(config); } void KisKraLoader::loadGuides(const KoXmlElement& elem) { QDomDocument dom; KoXml::asQDomElement(dom, elem); QDomElement domElement = dom.firstChildElement(); KisGuidesConfig guides; guides.loadFromXml(domElement); m_d->document->setGuidesConfig(guides); } void KisKraLoader::loadAudio(const KoXmlElement& elem, KisImageSP image) { QDomDocument dom; KoXml::asQDomElement(dom, elem); QDomElement qElement = dom.firstChildElement(); QString fileName; if (KisDomUtils::loadValue(qElement, "masterChannelPath", &fileName)) { fileName = QDir::toNativeSeparators(fileName); QDir baseDirectory = QFileInfo(m_d->document->localFilePath()).absoluteDir(); fileName = baseDirectory.absoluteFilePath(fileName); QFileInfo info(fileName); if (!info.exists()) { qApp->setOverrideCursor(Qt::ArrowCursor); QString msg = i18nc( "@info", "Audio channel file \"%1\" doesn't exist!\n\n" "Expected path:\n" "%2\n\n" "Do you want to locate it manually?", info.fileName(), info.absoluteFilePath()); int result = QMessageBox::warning(0, i18nc("@title:window", "File not found"), msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); if (result == QMessageBox::Yes) { info.setFile(KisImportExportManager::askForAudioFileName(info.absolutePath(), 0)); } qApp->restoreOverrideCursor(); } if (info.exists()) { image->animationInterface()->setAudioChannelFileName(info.absoluteFilePath()); } } bool audioMuted = false; if (KisDomUtils::loadValue(qElement, "audioMuted", &audioMuted)) { image->animationInterface()->setAudioMuted(audioMuted); } qreal audioVolume = 0.5; if (KisDomUtils::loadValue(qElement, "audioVolume", &audioVolume)) { image->animationInterface()->setAudioVolume(audioVolume); } } KisNodeSP KisKraLoader::loadReferenceImagesLayer(const KoXmlElement &elem, KisImageSP image) { KisSharedPtr layer = new KisReferenceImagesLayer(m_d->document->shapeController(), image); m_d->document->setReferenceImagesLayer(layer, false); for (QDomElement child = elem.firstChildElement(); !child.isNull(); child = child.nextSiblingElement()) { if (child.nodeName().toLower() == "referenceimage") { auto* reference = KisReferenceImage::fromXml(child); layer->addShape(reference); } } return layer; } diff --git a/plugins/impex/libkra/kis_kra_saver.cpp b/plugins/impex/libkra/kis_kra_saver.cpp index cebf9b4038..0bf2112f15 100644 --- a/plugins/impex/libkra/kis_kra_saver.cpp +++ b/plugins/impex/libkra/kis_kra_saver.cpp @@ -1,512 +1,512 @@ /* This file is part of the KDE project * Copyright 2008 (C) Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_kra_saver.h" #include "kis_kra_tags.h" #include "kis_kra_save_visitor.h" #include "kis_kra_savexml_visitor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_png_converter.h" #include "kis_keyframe_channel.h" #include #include "KisDocument.h" #include #include "kis_dom_utils.h" #include "kis_grid_config.h" #include "kis_guides_config.h" #include "KisProofingConfiguration.h" #include #include using namespace KRA; struct KisKraSaver::Private { public: KisDocument* doc; QMap nodeFileNames; QMap keyframeFilenames; QString imageName; QString filename; QStringList errorMessages; }; KisKraSaver::KisKraSaver(KisDocument* document, const QString &filename) : m_d(new Private) { m_d->doc = document; m_d->filename = filename; m_d->imageName = m_d->doc->documentInfo()->aboutInfo("title"); if (m_d->imageName.isEmpty()) { m_d->imageName = i18n("Unnamed"); } } KisKraSaver::~KisKraSaver() { delete m_d; } QDomElement KisKraSaver::saveXML(QDomDocument& doc, KisImageSP image) { QDomElement imageElement = doc.createElement("IMAGE"); Q_ASSERT(image); imageElement.setAttribute(NAME, m_d->imageName); imageElement.setAttribute(MIME, NATIVE_MIMETYPE); imageElement.setAttribute(WIDTH, KisDomUtils::toString(image->width())); imageElement.setAttribute(HEIGHT, KisDomUtils::toString(image->height())); imageElement.setAttribute(COLORSPACE_NAME, image->colorSpace()->id()); imageElement.setAttribute(DESCRIPTION, m_d->doc->documentInfo()->aboutInfo("comment")); // XXX: Save profile as blob inside the image, instead of the product name. if (image->profile() && image->profile()-> valid()) { imageElement.setAttribute(PROFILE, image->profile()->name()); } imageElement.setAttribute(X_RESOLUTION, KisDomUtils::toString(image->xRes()*72.0)); imageElement.setAttribute(Y_RESOLUTION, KisDomUtils::toString(image->yRes()*72.0)); //now the proofing options: if (image->proofingConfiguration()) { imageElement.setAttribute(PROOFINGPROFILENAME, KisDomUtils::toString(image->proofingConfiguration()->proofingProfile)); imageElement.setAttribute(PROOFINGMODEL, KisDomUtils::toString(image->proofingConfiguration()->proofingModel)); imageElement.setAttribute(PROOFINGDEPTH, KisDomUtils::toString(image->proofingConfiguration()->proofingDepth)); imageElement.setAttribute(PROOFINGINTENT, KisDomUtils::toString(image->proofingConfiguration()->intent)); imageElement.setAttribute(PROOFINGADAPTATIONSTATE, KisDomUtils::toString(image->proofingConfiguration()->adaptationState)); } quint32 count = 1; // We don't save the root layer, but it does count KisSaveXmlVisitor visitor(doc, imageElement, count, m_d->doc->url().toLocalFile(), true); visitor.setSelectedNodes({m_d->doc->preActivatedNode()}); image->rootLayer()->accept(visitor); m_d->errorMessages.append(visitor.errorMessages()); m_d->nodeFileNames = visitor.nodeFileNames(); m_d->keyframeFilenames = visitor.keyframeFileNames(); saveBackgroundColor(doc, imageElement, image); saveAssistantsGlobalColor(doc, imageElement); saveWarningColor(doc, imageElement, image); saveCompositions(doc, imageElement, image); saveAssistantsList(doc, imageElement); saveGrid(doc, imageElement); saveGuides(doc, imageElement); saveAudio(doc, imageElement); savePalettesToXML(doc, imageElement); QDomElement animationElement = doc.createElement("animation"); KisDomUtils::saveValue(&animationElement, "framerate", image->animationInterface()->framerate()); KisDomUtils::saveValue(&animationElement, "range", image->animationInterface()->fullClipRange()); KisDomUtils::saveValue(&animationElement, "currentTime", image->animationInterface()->currentUITime()); imageElement.appendChild(animationElement); return imageElement; } bool KisKraSaver::savePalettes(KoStore *store, KisImageSP image, const QString &uri) { Q_UNUSED(image); Q_UNUSED(uri); bool res = false; if (m_d->doc->paletteList().size() == 0) { return true; } - for (const KoColorSet *palette : m_d->doc->paletteList()) { + for (const KoColorSetSP palette : m_d->doc->paletteList()) { if (!palette->isGlobal()) { if (!store->open(m_d->imageName + PALETTE_PATH + palette->filename())) { m_d->errorMessages << i18n("could not save palettes"); return false; } QByteArray ba = palette->toByteArray(); if (!ba.isEmpty()) { store->write(ba); } else { qWarning() << "Cannot save the palette to a byte array:" << palette->name(); } store->close(); res = true; } } return res; } void KisKraSaver::savePalettesToXML(QDomDocument &doc, QDomElement &element) { QDomElement ePalette = doc.createElement(PALETTES); - for (const KoColorSet *palette : m_d->doc->paletteList()) { + for (const KoColorSetSP palette : m_d->doc->paletteList()) { if (!palette->isGlobal()) { QDomElement eFile = doc.createElement("palette"); eFile.setAttribute("filename", palette->filename()); ePalette.appendChild(eFile); } } element.appendChild(ePalette); } bool KisKraSaver::saveKeyframes(KoStore *store, const QString &uri, bool external) { QMap::iterator it; for (it = m_d->keyframeFilenames.begin(); it != m_d->keyframeFilenames.end(); it++) { const KisNode *node = it.key(); QString filename = it.value(); QString location = (external ? QString() : uri) + m_d->imageName + LAYER_PATH + filename; if (!saveNodeKeyframes(store, location, node)) { return false; } } return true; } bool KisKraSaver::saveNodeKeyframes(KoStore *store, QString location, const KisNode *node) { QDomDocument doc = KisDocument::createDomDocument("krita-keyframes", "keyframes", "1.0"); QDomElement root = doc.documentElement(); KisKeyframeChannel *channel; Q_FOREACH (channel, node->keyframeChannels()) { QDomElement element = channel->toXML(doc, m_d->nodeFileNames[node]); root.appendChild(element); } if (store->open(location)) { QByteArray xml = doc.toByteArray(); store->write(xml); store->close(); } else { m_d->errorMessages << i18n("could not save keyframes"); return false; } return true; } bool KisKraSaver::saveBinaryData(KoStore* store, KisImageSP image, const QString &uri, bool external, bool autosave) { QString location; // Save the layers data KisKraSaveVisitor visitor(store, m_d->imageName, m_d->nodeFileNames); if (external) visitor.setExternalUri(uri); image->rootLayer()->accept(visitor); m_d->errorMessages.append(visitor.errorMessages()); if (!m_d->errorMessages.isEmpty()) { return false; } // saving annotations // XXX this only saves EXIF and ICC info. This would probably need // a redesign of the dtd of the krita file to do this more generally correct // e.g. have tags or so. KisAnnotationSP annotation = image->annotation("exif"); if (annotation) { location = external ? QString() : uri; location += m_d->imageName + EXIF_PATH; if (store->open(location)) { store->write(annotation->annotation()); store->close(); } } if (image->profile()) { const KoColorProfile *profile = image->profile(); KisAnnotationSP annotation; if (profile) { QByteArray profileRawData = profile->rawData(); if (!profileRawData.isEmpty()) { if (profile->type() == "icc") { annotation = new KisAnnotation(ICC, profile->name(), profile->rawData()); } else { annotation = new KisAnnotation(PROFILE, profile->name(), profile->rawData()); } } } if (annotation) { location = external ? QString() : uri; location += m_d->imageName + ICC_PATH; if (store->open(location)) { store->write(annotation->annotation()); store->close(); } } } //This'll embed the profile used for proofing into the kra file. if (image->proofingConfiguration()) { const KoColorProfile *proofingProfile = KoColorSpaceRegistry::instance()->profileByName(image->proofingConfiguration()->proofingProfile); if (proofingProfile && proofingProfile->valid()) { QByteArray proofingProfileRaw = proofingProfile->rawData(); if (!proofingProfileRaw.isEmpty()) { annotation = new KisAnnotation(ICCPROOFINGPROFILE, proofingProfile->name(), proofingProfile->rawData()); } } if (annotation) { location = external ? QString() : uri; location += m_d->imageName + ICC_PROOFING_PATH; if (store->open(location)) { store->write(annotation->annotation()); store->close(); } } } { KisPSDLayerStyleCollectionResource collection("not-nexists.asl"); KIS_ASSERT_RECOVER_NOOP(!collection.valid()); collection.collectAllLayerStyles(image->root()); if (collection.valid()) { location = external ? QString() : uri; location += m_d->imageName + LAYER_STYLES_PATH; if (store->open(location)) { QBuffer aslBuffer; aslBuffer.open(QIODevice::WriteOnly); collection.saveToDevice(&aslBuffer); aslBuffer.close(); store->write(aslBuffer.buffer()); store->close(); } } } if (!autosave) { KisPaintDeviceSP dev = image->projection(); KisPNGConverter::saveDeviceToStore("mergedimage.png", image->bounds(), image->xRes(), image->yRes(), dev, store); } saveAssistants(store, uri,external); return true; } QStringList KisKraSaver::errorMessages() const { return m_d->errorMessages; } void KisKraSaver::saveBackgroundColor(QDomDocument& doc, QDomElement& element, KisImageSP image) { QDomElement e = doc.createElement(CANVASPROJECTIONCOLOR); KoColor color = image->defaultProjectionColor(); QByteArray colorData = QByteArray::fromRawData((const char*)color.data(), color.colorSpace()->pixelSize()); e.setAttribute(COLORBYTEDATA, QString(colorData.toBase64())); element.appendChild(e); } void KisKraSaver::saveAssistantsGlobalColor(QDomDocument& doc, QDomElement& element) { QDomElement e = doc.createElement(GLOBALASSISTANTSCOLOR); QString colorString = KisDomUtils::qColorToQString(m_d->doc->assistantsGlobalColor()); e.setAttribute(SIMPLECOLORDATA, QString(colorString)); element.appendChild(e); } void KisKraSaver::saveWarningColor(QDomDocument& doc, QDomElement& element, KisImageSP image) { if (image->proofingConfiguration()) { QDomElement e = doc.createElement(PROOFINGWARNINGCOLOR); KoColor color = image->proofingConfiguration()->warningColor; color.toXML(doc, e); element.appendChild(e); } } void KisKraSaver::saveCompositions(QDomDocument& doc, QDomElement& element, KisImageSP image) { if (!image->compositions().isEmpty()) { QDomElement e = doc.createElement("compositions"); Q_FOREACH (KisLayerCompositionSP composition, image->compositions()) { composition->save(doc, e); } element.appendChild(e); } } bool KisKraSaver::saveAssistants(KoStore* store, QString uri, bool external) { QString location; QMap assistantcounters; QByteArray data; QList assistants = m_d->doc->assistants(); QMap handlemap; if (!assistants.isEmpty()) { Q_FOREACH (KisPaintingAssistantSP assist, assistants){ if (!assistantcounters.contains(assist->id())){ assistantcounters.insert(assist->id(),0); } location = external ? QString() : uri; location += m_d->imageName + ASSISTANTS_PATH; location += QString(assist->id()+"%1.assistant").arg(assistantcounters[assist->id()]); data = assist->saveXml(handlemap); store->open(location); store->write(data); store->close(); assistantcounters[assist->id()]++; } } return true; } bool KisKraSaver::saveAssistantsList(QDomDocument& doc, QDomElement& element) { int count_ellipse = 0, count_perspective = 0, count_ruler = 0, count_vanishingpoint = 0,count_infiniteruler = 0, count_parallelruler = 0, count_concentricellipse = 0, count_fisheyepoint = 0, count_spline = 0; QList assistants = m_d->doc->assistants(); if (!assistants.isEmpty()) { QDomElement assistantsElement = doc.createElement("assistants"); Q_FOREACH (KisPaintingAssistantSP assist, assistants){ if (assist->id() == "ellipse"){ assist->saveXmlList(doc, assistantsElement, count_ellipse); count_ellipse++; } else if (assist->id() == "spline"){ assist->saveXmlList(doc, assistantsElement, count_spline); count_spline++; } else if (assist->id() == "perspective"){ assist->saveXmlList(doc, assistantsElement, count_perspective); count_perspective++; } else if (assist->id() == "vanishing point"){ assist->saveXmlList(doc, assistantsElement, count_vanishingpoint); count_vanishingpoint++; } else if (assist->id() == "infinite ruler"){ assist->saveXmlList(doc, assistantsElement, count_infiniteruler); count_infiniteruler++; } else if (assist->id() == "parallel ruler"){ assist->saveXmlList(doc, assistantsElement, count_parallelruler); count_parallelruler++; } else if (assist->id() == "concentric ellipse"){ assist->saveXmlList(doc, assistantsElement, count_concentricellipse); count_concentricellipse++; } else if (assist->id() == "fisheye-point"){ assist->saveXmlList(doc, assistantsElement, count_fisheyepoint); count_fisheyepoint++; } else if (assist->id() == "ruler"){ assist->saveXmlList(doc, assistantsElement, count_ruler); count_ruler++; } } element.appendChild(assistantsElement); } return true; } bool KisKraSaver::saveGrid(QDomDocument& doc, QDomElement& element) { KisGridConfig config = m_d->doc->gridConfig(); if (!config.isDefault()) { QDomElement gridElement = config.saveDynamicDataToXml(doc, "grid"); element.appendChild(gridElement); } return true; } bool KisKraSaver::saveGuides(QDomDocument& doc, QDomElement& element) { KisGuidesConfig guides = m_d->doc->guidesConfig(); if (!guides.isDefault()) { QDomElement guidesElement = guides.saveToXml(doc, "guides"); element.appendChild(guidesElement); } return true; } bool KisKraSaver::saveAudio(QDomDocument& doc, QDomElement& element) { const KisImageAnimationInterface *interface = m_d->doc->image()->animationInterface(); QString fileName = interface->audioChannelFileName(); if (fileName.isEmpty()) return true; if (!QFileInfo::exists(fileName)) { m_d->errorMessages << i18n("Audio channel file %1 doesn't exist!", fileName); return false; } const QDir documentDir = QFileInfo(m_d->filename).absoluteDir(); KIS_ASSERT_RECOVER_RETURN_VALUE(documentDir.exists(), false); fileName = documentDir.relativeFilePath(fileName); fileName = QDir::fromNativeSeparators(fileName); KIS_ASSERT_RECOVER_RETURN_VALUE(!fileName.isEmpty(), false); QDomElement audioElement = doc.createElement("audio"); KisDomUtils::saveValue(&audioElement, "masterChannelPath", fileName); KisDomUtils::saveValue(&audioElement, "audioMuted", interface->isAudioMuted()); KisDomUtils::saveValue(&audioElement, "audioVolume", interface->audioVolume()); element.appendChild(audioElement); return true; } diff --git a/plugins/impex/psd/psd_loader.cpp b/plugins/impex/psd/psd_loader.cpp index 0b99d9d1e6..26574f40fe 100644 --- a/plugins/impex/psd/psd_loader.cpp +++ b/plugins/impex/psd/psd_loader.cpp @@ -1,380 +1,379 @@ /* * Copyright (c) 2009 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 "psd_loader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisResourceServerProvider.h" #include "psd.h" #include "psd_header.h" #include "psd_colormode_block.h" #include "psd_utils.h" #include "psd_resource_section.h" #include "psd_layer_section.h" #include "psd_resource_block.h" #include "psd_image_data.h" PSDLoader::PSDLoader(KisDocument *doc) : m_image(0) , m_doc(doc) , m_stop(false) { } PSDLoader::~PSDLoader() { } KisImageBuilder_Result PSDLoader::decode(QIODevice *io) { // open the file dbgFile << "pos:" << io->pos(); PSDHeader header; if (!header.read( io)) { dbgFile << "failed reading header: " << header.error; return KisImageBuilder_RESULT_FAILURE; } dbgFile << header; dbgFile << "Read header. pos:" << io->pos(); PSDColorModeBlock colorModeBlock(header.colormode); if (!colorModeBlock.read(io)) { dbgFile << "failed reading colormode block: " << colorModeBlock.error; return KisImageBuilder_RESULT_FAILURE; } dbgFile << "Read color mode block. pos:" << io->pos(); PSDImageResourceSection resourceSection; if (!resourceSection.read(io)) { dbgFile << "failed image reading resource section: " << resourceSection.error; return KisImageBuilder_RESULT_FAILURE; } dbgFile << "Read image resource section. pos:" << io->pos(); PSDLayerMaskSection layerSection(header); if (!layerSection.read(io)) { dbgFile << "failed reading layer/mask section: " << layerSection.error; return KisImageBuilder_RESULT_FAILURE; } dbgFile << "Read layer/mask section. " << layerSection.nLayers << "layers. pos:" << io->pos(); // Done reading, except possibly for the image data block, which is only relevant if there // are no layers. // Get the right colorspace QPair colorSpaceId = psd_colormode_to_colormodelid(header.colormode, header.channelDepth); if (colorSpaceId.first.isNull()) { dbgFile << "Unsupported colorspace" << header.colormode << header.channelDepth; return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE; } // Get the icc profile from the image resource section const KoColorProfile* profile = 0; if (resourceSection.resources.contains(PSDImageResourceSection::ICC_PROFILE)) { ICC_PROFILE_1039 *iccProfileData = dynamic_cast(resourceSection.resources[PSDImageResourceSection::ICC_PROFILE]->resource); if (iccProfileData ) { profile = KoColorSpaceRegistry::instance()->createColorProfile(colorSpaceId.first, colorSpaceId.second, iccProfileData->icc); dbgFile << "Loaded ICC profile" << profile->name(); delete resourceSection.resources.take(PSDImageResourceSection::ICC_PROFILE); } } // Create the colorspace const KoColorSpace* cs = KoColorSpaceRegistry::instance()->colorSpace(colorSpaceId.first, colorSpaceId.second, profile); if (!cs) { return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE; } // Creating the KisImage QFile *file = dynamic_cast(io); QString name = file ? file->fileName() : "Imported"; m_image = new KisImage(m_doc->createUndoStore(), header.width, header.height, cs, name); Q_CHECK_PTR(m_image); m_image->lock(); // set the correct resolution if (resourceSection.resources.contains(PSDImageResourceSection::RESN_INFO)) { RESN_INFO_1005 *resInfo = dynamic_cast(resourceSection.resources[PSDImageResourceSection::RESN_INFO]->resource); if (resInfo) { // check resolution size is not zero if (resInfo->hRes * resInfo->vRes > 0) m_image->setResolution(POINT_TO_INCH(resInfo->hRes), POINT_TO_INCH(resInfo->vRes)); // let's skip the unit for now; we can only set that on the KisDocument, and krita doesn't use it. delete resourceSection.resources.take(PSDImageResourceSection::RESN_INFO); } } // Preserve all the annotations Q_FOREACH (PSDResourceBlock *resourceBlock, resourceSection.resources.values()) { m_image->addAnnotation(resourceBlock); } // Preserve the duotone colormode block for saving back to psd if (header.colormode == DuoTone) { KisAnnotationSP annotation = new KisAnnotation("DuotoneColormodeBlock", i18n("Duotone Colormode Block"), colorModeBlock.data); m_image->addAnnotation(annotation); } // Read the projection into our single layer. Since we only read the projection when // we have just one layer, we don't need to later on apply the alpha channel of the // first layer to the projection if the number of layers is negative/ // See http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577409_16000. if (layerSection.nLayers == 0) { dbgFile << "Position" << io->pos() << "Going to read the projection into the first layer, which Photoshop calls 'Background'"; KisPaintLayerSP layer = new KisPaintLayer(m_image, i18n("Background"), OPACITY_OPAQUE_U8); PSDImageData imageData(&header); imageData.read(io, layer->paintDevice()); m_image->addNode(layer, m_image->rootLayer()); // Only one layer, the background layer, so we're done. m_image->unlock(); return KisImageBuilder_RESULT_OK; } // More than one layer, so now construct the Krita image from the info we read. QStack groupStack; groupStack.push(m_image->rootLayer()); /** * PSD has a weird "optimization": if a group layer has only one * child layer, it omits it's 'psd_bounding_divider' section. So * fi you ever see an unbalanced layers group in PSD, most * probably, it is just a single layered group. */ KisNodeSP lastAddedLayer; typedef QPair LayerStyleMapping; QVector allStylesXml; // read the channels for the various layers for(int i = 0; i < layerSection.nLayers; ++i) { PSDLayerRecord* layerRecord = layerSection.layers.at(i); dbgFile << "Going to read channels for layer" << i << layerRecord->layerName; KisLayerSP newLayer; if (layerRecord->infoBlocks.keys.contains("lsct") && layerRecord->infoBlocks.sectionDividerType != psd_other) { if (layerRecord->infoBlocks.sectionDividerType == psd_bounding_divider && !groupStack.isEmpty()) { KisGroupLayerSP groupLayer = new KisGroupLayer(m_image, "temp", OPACITY_OPAQUE_U8); m_image->addNode(groupLayer, groupStack.top()); groupStack.push(groupLayer); newLayer = groupLayer; } else if ((layerRecord->infoBlocks.sectionDividerType == psd_open_folder || layerRecord->infoBlocks.sectionDividerType == psd_closed_folder) && (groupStack.size() > 1 || (lastAddedLayer && !groupStack.isEmpty()))) { KisGroupLayerSP groupLayer; if (groupStack.size() <= 1) { groupLayer = new KisGroupLayer(m_image, "temp", OPACITY_OPAQUE_U8); m_image->addNode(groupLayer, groupStack.top()); m_image->moveNode(lastAddedLayer, groupLayer, KisNodeSP()); } else { groupLayer = groupStack.pop(); } const QDomDocument &styleXml = layerRecord->infoBlocks.layerStyleXml; if (!styleXml.isNull()) { allStylesXml << LayerStyleMapping(styleXml, groupLayer); } groupLayer->setName(layerRecord->layerName); groupLayer->setVisible(layerRecord->visible); QString compositeOp = psd_blendmode_to_composite_op(layerRecord->infoBlocks.sectionDividerBlendMode); // Krita doesn't support pass-through blend // mode. Instead it is just a property of a group // layer, so flip it if (compositeOp == COMPOSITE_PASS_THROUGH) { compositeOp = COMPOSITE_OVER; groupLayer->setPassThroughMode(true); } groupLayer->setCompositeOpId(compositeOp); newLayer = groupLayer; } else { /** * In some files saved by PS CS6 the group layer sections seem * to be unbalanced. I don't know why it happens because the * reporter didn't provide us an example file. So here we just * check if the new layer was created, and if not, skip the * initialization of masks. * * See bug: 357559 */ warnKrita << "WARNING: Provided PSD has unbalanced group " << "layer markers. Some masks and/or layers can " << "be lost while loading this file. Please " << "report a bug to Krita developers and attach " << "this file to the bugreport\n" << " " << ppVar(layerRecord->layerName) << "\n" << " " << ppVar(layerRecord->infoBlocks.sectionDividerType) << "\n" << " " << ppVar(groupStack.size()); continue; } } else { KisPaintLayerSP layer = new KisPaintLayer(m_image, layerRecord->layerName, layerRecord->opacity); layer->setCompositeOpId(psd_blendmode_to_composite_op(layerRecord->blendModeKey)); const QDomDocument &styleXml = layerRecord->infoBlocks.layerStyleXml; if (!styleXml.isNull()) { allStylesXml << LayerStyleMapping(styleXml, layer); } if (!layerRecord->readPixelData(io, layer->paintDevice())) { dbgFile << "failed reading channels for layer: " << layerRecord->layerName << layerRecord->error; return KisImageBuilder_RESULT_FAILURE; } if (!groupStack.isEmpty()) { m_image->addNode(layer, groupStack.top()); } else { m_image->addNode(layer, m_image->root()); } layer->setVisible(layerRecord->visible); newLayer = layer; } Q_FOREACH (ChannelInfo *channelInfo, layerRecord->channelInfoRecords) { if (channelInfo->channelId < -1) { KisTransparencyMaskSP mask = new KisTransparencyMask(); mask->setName(i18n("Transparency Mask")); mask->initSelection(newLayer); if (!layerRecord->readMask(io, mask->paintDevice(), channelInfo)) { dbgFile << "failed reading masks for layer: " << layerRecord->layerName << layerRecord->error; } m_image->addNode(mask, newLayer); } } lastAddedLayer = newLayer; } const QVector &embeddedPatterns = layerSection.globalInfoSection.embeddedPatterns; KisAslLayerStyleSerializer serializer; if (!embeddedPatterns.isEmpty()) { Q_FOREACH (const QDomDocument &doc, embeddedPatterns) { serializer.registerPSDPattern(doc); } } QVector allStylesForServer; if (!allStylesXml.isEmpty()) { Q_FOREACH (const LayerStyleMapping &mapping, allStylesXml) { serializer.readFromPSDXML(mapping.first); if (serializer.styles().size() == 1) { KisPSDLayerStyleSP layerStyle = serializer.styles().first(); KisLayerSP layer = mapping.second; layerStyle->setName(layer->name()); allStylesForServer << layerStyle; layer->setLayerStyle(layerStyle->clone()); } else { warnKrita << "WARNING: Couldn't read layer style!" << ppVar(serializer.styles()); } } } if (!allStylesForServer.isEmpty()) { - KisPSDLayerStyleCollectionResource *collection = - new KisPSDLayerStyleCollectionResource("Embedded PSD Styles.asl"); + KisPSDLayerStyleCollectionResourceSP collection(new KisPSDLayerStyleCollectionResource("Embedded PSD Styles.asl")); collection->setName(i18nc("Auto-generated layer style collection name for embedded styles (collection)", "<%1> (embedded)", m_image->objectName())); KIS_SAFE_ASSERT_RECOVER_NOOP(!collection->valid()); collection->setLayerStyles(allStylesForServer); KIS_SAFE_ASSERT_RECOVER_NOOP(collection->valid()); KoResourceServer *server = KisResourceServerProvider::instance()->layerStyleCollectionServer(); server->addResource(collection, false); } m_image->unlock(); return KisImageBuilder_RESULT_OK; } KisImageBuilder_Result PSDLoader::buildImage(QIODevice *io) { return decode(io); } KisImageSP PSDLoader::image() { return m_image; } void PSDLoader::cancel() { m_stop = true; } diff --git a/plugins/paintops/colorsmudge/kis_colorsmudgeop.h b/plugins/paintops/colorsmudge/kis_colorsmudgeop.h index 8a1928a899..239edb8c97 100644 --- a/plugins/paintops/colorsmudge/kis_colorsmudgeop.h +++ b/plugins/paintops/colorsmudge/kis_colorsmudgeop.h @@ -1,95 +1,97 @@ /* * Copyright (C) 2011 Silvio Heinrich * * 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_COLORSMUDGEOP_H_ #define _KIS_COLORSMUDGEOP_H_ #include +#include "KoColorTransformation.h" +#include + #include #include #include #include #include #include #include #include #include -#include "KoColorTransformation.h" #include "kis_overlay_mode_option.h" #include "kis_rate_option.h" #include "kis_smudge_option.h" #include "kis_smudge_radius_option.h" #include "KisPrecisePaintDeviceWrapper.h" class QPointF; -class KoAbstractGradient; + class KisBrushBasedPaintOpSettings; class KisPainter; class KoColorSpace; class KisColorSmudgeOp: public KisBrushBasedPaintOp { public: KisColorSmudgeOp(const KisPaintOpSettingsSP settings, KisPainter* painter, KisNodeSP node, KisImageSP image); ~KisColorSmudgeOp() override; protected: KisSpacingInformation paintAt(const KisPaintInformation& info) override; KisSpacingInformation updateSpacingImpl(const KisPaintInformation &info) const override; private: // Sets the m_maskDab _and m_maskDabRect void updateMask(const KisPaintInformation& info, double scale, double rotation, const QPointF &cursorPoint); inline void getTopLeftAligned(const QPointF &pos, const QPointF &hotSpot, qint32 *x, qint32 *y); private: bool m_firstRun; KisImageWSP m_image; KisPrecisePaintDeviceWrapper m_precisePainterWrapper; KoColor m_paintColor; KisPaintDeviceSP m_tempDev; QScopedPointer m_preciseImageDeviceWrapper; QScopedPointer m_backgroundPainter; QScopedPointer m_smudgePainter; QScopedPointer m_colorRatePainter; QScopedPointer m_finalPainter; - const KoAbstractGradient* m_gradient {0}; + KoAbstractGradientSP m_gradient; KisPressureSizeOption m_sizeOption; KisPressureOpacityOption m_opacityOption; KisPressureSpacingOption m_spacingOption; KisSmudgeOption m_smudgeRateOption; KisRateOption m_colorRateOption; KisSmudgeRadiusOption m_smudgeRadiusOption; KisOverlayModeOption m_overlayModeOption; KisPressureRotationOption m_rotationOption; KisPressureScatterOption m_scatterOption; KisPressureGradientOption m_gradientOption; QList m_hsvOptions; QRect m_dstDabRect; KisFixedPaintDeviceSP m_maskDab; QPointF m_lastPaintPos; KoColorTransformation *m_hsvTransform {0}; const KoCompositeOp *m_preciseColorRateCompositeOp {0}; }; #endif // _KIS_COLORSMUDGEOP_H_ diff --git a/plugins/paintops/colorsmudge/kis_colorsmudgeop_settings.cpp b/plugins/paintops/colorsmudge/kis_colorsmudgeop_settings.cpp index f51fcbcced..84d0e49ea8 100644 --- a/plugins/paintops/colorsmudge/kis_colorsmudgeop_settings.cpp +++ b/plugins/paintops/colorsmudge/kis_colorsmudgeop_settings.cpp @@ -1,121 +1,125 @@ /* * Copyright (c) 2016 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_colorsmudgeop_settings.h" #include "kis_smudge_option.h" struct KisColorSmudgeOpSettings::Private { QList uniformProperties; }; KisColorSmudgeOpSettings::KisColorSmudgeOpSettings() : m_d(new Private) { } KisColorSmudgeOpSettings::~KisColorSmudgeOpSettings() { } #include #include #include "kis_paintop_preset.h" #include "kis_paintop_settings_update_proxy.h" #include "kis_curve_option_uniform_property.h" #include "kis_smudge_radius_option.h" QList KisColorSmudgeOpSettings::uniformProperties(KisPaintOpSettingsSP settings) { QList props = listWeakToStrong(m_d->uniformProperties); if (props.isEmpty()) { { KisComboBasedPaintOpPropertyCallback *prop = new KisComboBasedPaintOpPropertyCallback( "smudge_mode", i18n("Smudge Mode"), settings, 0); QList modes; modes << i18n("Smearing"); modes << i18n("Dulling"); prop->setItems(modes); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { KisSmudgeOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(int(option.getMode())); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { KisSmudgeOption option; option.readOptionSetting(prop->settings().data()); option.setMode(KisSmudgeOption::Mode(prop->value().toInt())); option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisCurveOptionUniformProperty *prop = new KisCurveOptionUniformProperty( "smudge_length", new KisSmudgeOption(), settings, 0); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisCurveOptionUniformProperty *prop = new KisCurveOptionUniformProperty( "smudge_radius", new KisSmudgeRadiusOption(), settings, 0); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisCurveOptionUniformProperty *prop = new KisCurveOptionUniformProperty( "smudge_color_rate", new KisRateOption("ColorRate", KisPaintOpOption::GENERAL, false), settings, 0); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } } return KisBrushBasedPaintOpSettings::uniformProperties(settings) + props; } diff --git a/plugins/paintops/curvebrush/kis_curve_paintop_settings.cpp b/plugins/paintops/curvebrush/kis_curve_paintop_settings.cpp index 2dcd0d00b4..b6b8c42c5b 100644 --- a/plugins/paintops/curvebrush/kis_curve_paintop_settings.cpp +++ b/plugins/paintops/curvebrush/kis_curve_paintop_settings.cpp @@ -1,203 +1,206 @@ /* * Copyright (c) 2008,2009 Lukáš Tvrdý * * 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 #include #include "kis_curve_line_option.h" struct KisCurvePaintOpSettings::Private { QList uniformProperties; }; KisCurvePaintOpSettings::KisCurvePaintOpSettings() : m_d(new Private) { } KisCurvePaintOpSettings::~KisCurvePaintOpSettings() { } void KisCurvePaintOpSettings::setPaintOpSize(qreal value) { KisCurveOptionProperties option; option.readOptionSetting(this); option.curve_line_width = value; option.writeOptionSetting(this); } qreal KisCurvePaintOpSettings::paintOpSize() const { KisCurveOptionProperties option; option.readOptionSetting(this); return option.curve_line_width; } bool KisCurvePaintOpSettings::paintIncremental() { return (enumPaintActionType)getInt("PaintOpAction", WASH) == BUILDUP; } #include #include "kis_paintop_preset.h" #include "kis_paintop_settings_update_proxy.h" #include "kis_standard_uniform_properties_factory.h" QList KisCurvePaintOpSettings::uniformProperties(KisPaintOpSettingsSP settings) { QList props = listWeakToStrong(m_d->uniformProperties); if (props.isEmpty()) { { KisIntSliderBasedPaintOpPropertyCallback *prop = new KisIntSliderBasedPaintOpPropertyCallback( KisIntSliderBasedPaintOpPropertyCallback::Int, "curve_linewidth", i18n("Line Width"), settings, 0); prop->setRange(1, 100); prop->setSingleStep(1); prop->setSuffix(i18n(" px")); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { KisCurveOptionProperties option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.curve_line_width); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { KisCurveOptionProperties option; option.readOptionSetting(prop->settings().data()); option.curve_line_width = prop->value().toInt(); option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisIntSliderBasedPaintOpPropertyCallback *prop = new KisIntSliderBasedPaintOpPropertyCallback( KisIntSliderBasedPaintOpPropertyCallback::Int, "curve_historysize", i18n("History Size"), settings, 0); prop->setRange(2, 300); prop->setSingleStep(1); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { KisCurveOptionProperties option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.curve_stroke_history_size); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { KisCurveOptionProperties option; option.readOptionSetting(prop->settings().data()); option.curve_stroke_history_size = prop->value().toInt(); option.writeOptionSetting(prop->settings().data()); }); - - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisDoubleSliderBasedPaintOpPropertyCallback *prop = new KisDoubleSliderBasedPaintOpPropertyCallback( KisDoubleSliderBasedPaintOpPropertyCallback::Double, "curve_lineopacity", i18n("Line Opacity"), settings, 0); prop->setRange(0, 100.0); prop->setSingleStep(0.01); prop->setDecimals(2); prop->setSuffix(i18n("%")); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { KisCurveOptionProperties option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.curve_curves_opacity * 100.0); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { KisCurveOptionProperties option; option.readOptionSetting(prop->settings().data()); option.curve_curves_opacity = prop->value().toReal() / 100.0; option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisUniformPaintOpPropertyCallback *prop = new KisUniformPaintOpPropertyCallback( KisUniformPaintOpPropertyCallback::Bool, "curve_connectionline", i18n("Connection Line"), settings, 0); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { KisCurveOptionProperties option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.curve_paint_connection_line); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { KisCurveOptionProperties option; option.readOptionSetting(prop->settings().data()); option.curve_paint_connection_line = prop->value().toBool(); option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } } { using namespace KisStandardUniformPropertiesFactory; Q_FOREACH (KisUniformPaintOpPropertySP prop, KisPaintOpSettings::uniformProperties(settings)) { if (prop->id() == opacity.id()) { props.prepend(prop); } } } return props; } diff --git a/plugins/paintops/defaultpaintops/brush/tests/KisDabRenderingQueueTest.cpp b/plugins/paintops/defaultpaintops/brush/tests/KisDabRenderingQueueTest.cpp index c72f7603b4..f75c35284a 100644 --- a/plugins/paintops/defaultpaintops/brush/tests/KisDabRenderingQueueTest.cpp +++ b/plugins/paintops/defaultpaintops/brush/tests/KisDabRenderingQueueTest.cpp @@ -1,541 +1,541 @@ /* * Copyright (c) 2017 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 "KisDabRenderingQueueTest.h" #include #include #include #include <../KisDabRenderingQueue.h> #include <../KisRenderedDab.h> #include <../KisDabRenderingJob.h> struct SurrogateCacheInterface : public KisDabRenderingQueue::CacheInterface { void getDabType(bool hasDabInCache, KisDabCacheUtils::DabRenderingResources *resources, const KisDabCacheUtils::DabRequestInfo &request, /* out */ KisDabCacheUtils::DabGenerationInfo *di, bool *shouldUseCache) override { Q_UNUSED(resources); Q_UNUSED(request); if (!hasDabInCache || typeOverride == KisDabRenderingJob::Dab) { di->needsPostprocessing = false; *shouldUseCache = false; } else if (typeOverride == KisDabRenderingJob::Copy) { di->needsPostprocessing = false; *shouldUseCache = true; } else if (typeOverride == KisDabRenderingJob::Postprocess) { di->needsPostprocessing = true; *shouldUseCache = true; } di->info = request.info; } bool hasSeparateOriginal(KisDabCacheUtils::DabRenderingResources *resources) const override { Q_UNUSED(resources); return typeOverride == KisDabRenderingJob::Postprocess; } KisDabRenderingJob::JobType typeOverride = KisDabRenderingJob::Dab; }; #include #include "kis_auto_brush.h" KisDabCacheUtils::DabRenderingResources *testResourcesFactory() { KisDabCacheUtils::DabRenderingResources *resources = new KisDabCacheUtils::DabRenderingResources(); KisCircleMaskGenerator* circle = new KisCircleMaskGenerator(10, 1.0, 1.0, 1.0, 2, false); - KisBrushSP brush = new KisAutoBrush(circle, 0.0, 0.0); + KisBrushSP brush(new KisAutoBrush(circle, 0.0, 0.0)); resources->brush = brush; return resources; } void KisDabRenderingQueueTest::testCachedDabs() { const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8(); SurrogateCacheInterface *cacheInterface = new SurrogateCacheInterface(); KisDabRenderingQueue queue(cs, testResourcesFactory); queue.setCacheInterface(cacheInterface); KoColor color; QPointF pos1(10,10); QPointF pos2(20,20); KisDabShape shape; KisPaintInformation pi1(pos1); KisPaintInformation pi2(pos2); KisDabCacheUtils::DabRequestInfo request1(color, pos1, shape, pi1, 1.0); KisDabCacheUtils::DabRequestInfo request2(color, pos2, shape, pi2, 1.0); cacheInterface->typeOverride = KisDabRenderingJob::Dab; KisDabRenderingJobSP job0 = queue.addDab(request1, OPACITY_OPAQUE_F, OPACITY_OPAQUE_F); QVERIFY(job0); QCOMPARE(job0->seqNo, 0); QCOMPARE(job0->generationInfo.info.pos(), request1.info.pos()); QCOMPARE(job0->type, KisDabRenderingJob::Dab); QVERIFY(!job0->originalDevice); QVERIFY(!job0->postprocessedDevice); cacheInterface->typeOverride = KisDabRenderingJob::Dab; KisDabRenderingJobSP job1 = queue.addDab(request2, OPACITY_OPAQUE_F, OPACITY_OPAQUE_F); QVERIFY(job1); QCOMPARE(job1->seqNo, 1); QCOMPARE(job1->generationInfo.info.pos(), request2.info.pos()); QCOMPARE(job1->type, KisDabRenderingJob::Dab); QVERIFY(!job1->originalDevice); QVERIFY(!job1->postprocessedDevice); cacheInterface->typeOverride = KisDabRenderingJob::Copy; KisDabRenderingJobSP job2 = queue.addDab(request2, OPACITY_OPAQUE_F, OPACITY_OPAQUE_F); QVERIFY(!job2); cacheInterface->typeOverride = KisDabRenderingJob::Copy; KisDabRenderingJobSP job3 = queue.addDab(request2, OPACITY_OPAQUE_F, OPACITY_OPAQUE_F); QVERIFY(!job3); // we only added the dabs, but we haven't completed them yet QVERIFY(!queue.hasPreparedDabs()); QCOMPARE(queue.testingGetQueueSize(), 4); QList jobs; QList renderedDabs; { // we've completed job0 job0->originalDevice = new KisFixedPaintDevice(cs); job0->postprocessedDevice = job0->originalDevice; jobs = queue.notifyJobFinished(job0->seqNo); QVERIFY(jobs.isEmpty()); // now we should have at least one job in prepared state QVERIFY(queue.hasPreparedDabs()); // take the prepared dabs renderedDabs = queue.takeReadyDabs(); QCOMPARE(renderedDabs.size(), 1); // the list should be empty again QVERIFY(!queue.hasPreparedDabs()); QCOMPARE(queue.testingGetQueueSize(), 3); } { // we've completed job1 job1->originalDevice = new KisFixedPaintDevice(cs); job1->postprocessedDevice = job1->originalDevice; jobs = queue.notifyJobFinished(job1->seqNo); QVERIFY(jobs.isEmpty()); // now we should have at least one job in prepared state QVERIFY(queue.hasPreparedDabs()); // take the prepared dabs renderedDabs = queue.takeReadyDabs(); QCOMPARE(renderedDabs.size(), 3); // since they are copies, they should be the same QCOMPARE(renderedDabs[1].device, renderedDabs[0].device); QCOMPARE(renderedDabs[2].device, renderedDabs[0].device); // the list should be empty again QVERIFY(!queue.hasPreparedDabs()); // we delete all the painted jobs except the latest 'dab' job QCOMPARE(queue.testingGetQueueSize(), 1); } { // add one more cached job and take it cacheInterface->typeOverride = KisDabRenderingJob::Copy; KisDabRenderingJobSP job = queue.addDab(request2, OPACITY_OPAQUE_F, OPACITY_OPAQUE_F); QVERIFY(!job); // now we should have at least one job in prepared state QVERIFY(queue.hasPreparedDabs()); // take the prepared dabs renderedDabs = queue.takeReadyDabs(); QCOMPARE(renderedDabs.size(), 1); // the list should be empty again QVERIFY(!queue.hasPreparedDabs()); // we delete all the painted jobs except the latest 'dab' job QCOMPARE(queue.testingGetQueueSize(), 1); } { // add a 'dab' job and complete it cacheInterface->typeOverride = KisDabRenderingJob::Dab; KisDabRenderingJobSP job = queue.addDab(request1, OPACITY_OPAQUE_F, OPACITY_OPAQUE_F); QVERIFY(job); QCOMPARE(job->seqNo, 5); QCOMPARE(job->generationInfo.info.pos(), request1.info.pos()); QCOMPARE(job->type, KisDabRenderingJob::Dab); QVERIFY(!job->originalDevice); QVERIFY(!job->postprocessedDevice); // now the queue can be cleared from the completed dabs! QCOMPARE(queue.testingGetQueueSize(), 1); job->originalDevice = new KisFixedPaintDevice(cs); job->postprocessedDevice = job->originalDevice; jobs = queue.notifyJobFinished(job->seqNo); QVERIFY(jobs.isEmpty()); // now we should have at least one job in prepared state QVERIFY(queue.hasPreparedDabs()); // take the prepared dabs renderedDabs = queue.takeReadyDabs(); QCOMPARE(renderedDabs.size(), 1); // the list should be empty again QVERIFY(!queue.hasPreparedDabs()); // we do not delete the queue of jobs until the next 'dab' // job arrives QCOMPARE(queue.testingGetQueueSize(), 1); } } void KisDabRenderingQueueTest::testPostprocessedDabs() { const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8(); SurrogateCacheInterface *cacheInterface = new SurrogateCacheInterface(); KisDabRenderingQueue queue(cs, testResourcesFactory); queue.setCacheInterface(cacheInterface); KoColor color; QPointF pos1(10,10); QPointF pos2(20,20); KisDabShape shape; KisPaintInformation pi1(pos1); KisPaintInformation pi2(pos2); KisDabCacheUtils::DabRequestInfo request1(color, pos1, shape, pi1, 1.0); KisDabCacheUtils::DabRequestInfo request2(color, pos2, shape, pi2, 1.0); cacheInterface->typeOverride = KisDabRenderingJob::Dab; KisDabRenderingJobSP job0 = queue.addDab(request1, OPACITY_OPAQUE_F, OPACITY_OPAQUE_F); QVERIFY(job0); QCOMPARE(job0->seqNo, 0); QCOMPARE(job0->generationInfo.info.pos(), request1.info.pos()); QCOMPARE(job0->type, KisDabRenderingJob::Dab); QVERIFY(!job0->originalDevice); QVERIFY(!job0->postprocessedDevice); cacheInterface->typeOverride = KisDabRenderingJob::Dab; KisDabRenderingJobSP job1 = queue.addDab(request2, OPACITY_OPAQUE_F, OPACITY_OPAQUE_F); QVERIFY(job1); QCOMPARE(job1->seqNo, 1); QCOMPARE(job1->generationInfo.info.pos(), request2.info.pos()); QCOMPARE(job1->type, KisDabRenderingJob::Dab); QVERIFY(!job1->originalDevice); QVERIFY(!job1->postprocessedDevice); cacheInterface->typeOverride = KisDabRenderingJob::Postprocess; KisDabRenderingJobSP job2 = queue.addDab(request2, OPACITY_OPAQUE_F, OPACITY_OPAQUE_F); QVERIFY(!job2); cacheInterface->typeOverride = KisDabRenderingJob::Postprocess; KisDabRenderingJobSP job3 = queue.addDab(request2, OPACITY_OPAQUE_F, OPACITY_OPAQUE_F); QVERIFY(!job3); // we only added the dabs, but we haven't completed them yet QVERIFY(!queue.hasPreparedDabs()); QCOMPARE(queue.testingGetQueueSize(), 4); QList jobs; QList renderedDabs; { // we've completed job0 job0->originalDevice = new KisFixedPaintDevice(cs); job0->postprocessedDevice = job0->originalDevice; jobs = queue.notifyJobFinished(job0->seqNo); QVERIFY(jobs.isEmpty()); // now we should have at least one job in prepared state QVERIFY(queue.hasPreparedDabs()); // take the prepared dabs renderedDabs = queue.takeReadyDabs(); QCOMPARE(renderedDabs.size(), 1); // the list should be empty again QVERIFY(!queue.hasPreparedDabs()); QCOMPARE(queue.testingGetQueueSize(), 3); } { // we've completed job1 job1->originalDevice = new KisFixedPaintDevice(cs); job1->postprocessedDevice = job1->originalDevice; jobs = queue.notifyJobFinished(job1->seqNo); QCOMPARE(jobs.size(), 2); QCOMPARE(jobs[0]->seqNo, 2); QCOMPARE(jobs[1]->seqNo, 3); QVERIFY(jobs[0]->originalDevice); QVERIFY(!jobs[0]->postprocessedDevice); QVERIFY(jobs[1]->originalDevice); QVERIFY(!jobs[1]->postprocessedDevice); // pretend we have created a postprocessed device jobs[0]->postprocessedDevice = new KisFixedPaintDevice(cs); jobs[1]->postprocessedDevice = new KisFixedPaintDevice(cs); // now we should have at least one job in prepared state QVERIFY(queue.hasPreparedDabs()); // take the prepared dabs renderedDabs = queue.takeReadyDabs(); QCOMPARE(renderedDabs.size(), 1); // the list should be empty again QVERIFY(!queue.hasPreparedDabs()); // return back two postprocessed dabs QList emptyJobs; emptyJobs = queue.notifyJobFinished(jobs[0]->seqNo); QVERIFY(emptyJobs.isEmpty()); emptyJobs = queue.notifyJobFinished(jobs[1]->seqNo); QVERIFY(emptyJobs.isEmpty()); // now we should have at least one job in prepared state QVERIFY(queue.hasPreparedDabs()); // take the prepared dabs renderedDabs = queue.takeReadyDabs(); QCOMPARE(renderedDabs.size(), 2); // the list should be empty again QVERIFY(!queue.hasPreparedDabs()); // we delete all the painted jobs except the latest 'dab' job QCOMPARE(queue.testingGetQueueSize(), 1); } { // add one more postprocessed job and take it cacheInterface->typeOverride = KisDabRenderingJob::Postprocess; KisDabRenderingJobSP job = queue.addDab(request2, OPACITY_OPAQUE_F, OPACITY_OPAQUE_F); QVERIFY(job); QCOMPARE(job->seqNo, 4); QCOMPARE(job->generationInfo.info.pos(), request2.info.pos()); ENTER_FUNCTION() << ppVar(job->type); QCOMPARE(job->type, KisDabRenderingJob::Postprocess); QVERIFY(job->originalDevice); QVERIFY(!job->postprocessedDevice); // the list should still be empty QVERIFY(!queue.hasPreparedDabs()); // pretend we have created a postprocessed device job->postprocessedDevice = new KisFixedPaintDevice(cs); // return back the postprocessed dab QList emptyJobs; emptyJobs = queue.notifyJobFinished(job->seqNo); QVERIFY(emptyJobs.isEmpty()); // now we should have at least one job in prepared state QVERIFY(queue.hasPreparedDabs()); // take the prepared dabs renderedDabs = queue.takeReadyDabs(); QCOMPARE(renderedDabs.size(), 1); // the list should be empty again QVERIFY(!queue.hasPreparedDabs()); // we delete all the painted jobs except the latest 'dab' job QCOMPARE(queue.testingGetQueueSize(), 1); } { // add a 'dab' job and complete it. That will clear the queue! cacheInterface->typeOverride = KisDabRenderingJob::Dab; KisDabRenderingJobSP job = queue.addDab(request1, OPACITY_OPAQUE_F, OPACITY_OPAQUE_F); QVERIFY(job); QCOMPARE(job->seqNo, 5); QCOMPARE(job->generationInfo.info.pos(), request1.info.pos()); QCOMPARE(job->type, KisDabRenderingJob::Dab); QVERIFY(!job->originalDevice); QVERIFY(!job->postprocessedDevice); // now the queue can be cleared from the completed dabs! QCOMPARE(queue.testingGetQueueSize(), 1); job->originalDevice = new KisFixedPaintDevice(cs); job->postprocessedDevice = job->originalDevice; jobs = queue.notifyJobFinished(job->seqNo); QVERIFY(jobs.isEmpty()); // now we should have at least one job in prepared state QVERIFY(queue.hasPreparedDabs()); // take the prepared dabs renderedDabs = queue.takeReadyDabs(); QCOMPARE(renderedDabs.size(), 1); // the list should be empty again QVERIFY(!queue.hasPreparedDabs()); // we do not delete the queue of jobs until the next 'dab' // job arrives QCOMPARE(queue.testingGetQueueSize(), 1); } } #include <../KisDabRenderingQueueCache.h> void KisDabRenderingQueueTest::testRunningJobs() { const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8(); KisDabRenderingQueueCache *cacheInterface = new KisDabRenderingQueueCache(); // we do *not* initialize any options yet! KisDabRenderingQueue queue(cs, testResourcesFactory); queue.setCacheInterface(cacheInterface); KoColor color(Qt::red, cs); QPointF pos1(10,10); QPointF pos2(20,20); KisDabShape shape; KisPaintInformation pi1(pos1); KisPaintInformation pi2(pos2); KisDabCacheUtils::DabRequestInfo request1(color, pos1, shape, pi1, 1.0); KisDabCacheUtils::DabRequestInfo request2(color, pos2, shape, pi2, 1.0); KisDabRenderingJobSP job0 = queue.addDab(request1, OPACITY_OPAQUE_F, OPACITY_OPAQUE_F); QVERIFY(job0); QCOMPARE(job0->seqNo, 0); QCOMPARE(job0->generationInfo.info.pos(), request1.info.pos()); QCOMPARE(job0->type, KisDabRenderingJob::Dab); QVERIFY(!job0->originalDevice); QVERIFY(!job0->postprocessedDevice); KisDabRenderingJobRunner runner(job0, &queue, 0); runner.run(); QVERIFY(job0->originalDevice); QVERIFY(job0->postprocessedDevice); QCOMPARE(job0->originalDevice, job0->postprocessedDevice); QVERIFY(!job0->originalDevice->bounds().isEmpty()); KisDabRenderingJobSP job1 = queue.addDab(request2, OPACITY_OPAQUE_F, OPACITY_OPAQUE_F); QVERIFY(!job1); QList renderedDabs = queue.takeReadyDabs(); QCOMPARE(renderedDabs.size(), 2); // we did the caching QVERIFY(renderedDabs[0].device == renderedDabs[1].device); QCOMPARE(renderedDabs[0].offset, QPoint(5,5)); QCOMPARE(renderedDabs[1].offset, QPoint(15,15)); } #include "../KisDabRenderingExecutor.h" #include "KisFakeRunnableStrokeJobsExecutor.h" void KisDabRenderingQueueTest::testExecutor() { const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8(); QScopedPointer runner(new KisFakeRunnableStrokeJobsExecutor()); KisDabRenderingExecutor executor(cs, testResourcesFactory, runner.data()); KoColor color(Qt::red, cs); QPointF pos1(10,10); QPointF pos2(20,20); KisDabShape shape; KisPaintInformation pi1(pos1); KisPaintInformation pi2(pos2); KisDabCacheUtils::DabRequestInfo request1(color, pos1, shape, pi1, 1.0); KisDabCacheUtils::DabRequestInfo request2(color, pos2, shape, pi2, 1.0); executor.addDab(request1, 0.5, 0.25); executor.addDab(request2, 0.125, 1.0); QList renderedDabs = executor.takeReadyDabs(); QCOMPARE(renderedDabs.size(), 2); // we did the caching QVERIFY(renderedDabs[0].device == renderedDabs[1].device); QCOMPARE(renderedDabs[0].offset, QPoint(5,5)); QCOMPARE(renderedDabs[1].offset, QPoint(15,15)); QCOMPARE(renderedDabs[0].opacity, 0.5); QCOMPARE(renderedDabs[0].flow, 0.25); QCOMPARE(renderedDabs[1].opacity, 0.125); QCOMPARE(renderedDabs[1].flow, 1.0); } QTEST_MAIN(KisDabRenderingQueueTest) diff --git a/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings.cpp b/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings.cpp index 33d4c928ab..0f40c3bb10 100644 --- a/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings.cpp +++ b/plugins/paintops/defaultpaintops/duplicate/kis_duplicateop_settings.cpp @@ -1,245 +1,247 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2004-2008 Boudewijn Rempt * Copyright (c) 2004 Clarence Dang * Copyright (c) 2004 Adrian Page * Copyright (c) 2004 Cyrille Berger * * 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_duplicateop_settings.h" #include "kis_duplicateop_option.h" #include "kis_duplicateop_settings_widget.h" #include #include #include #include #include #include #include #include #include #include #include #include KisDuplicateOpSettings::KisDuplicateOpSettings() : m_isOffsetNotUptodate(false) { } KisDuplicateOpSettings::~KisDuplicateOpSettings() { } bool KisDuplicateOpSettings::paintIncremental() { return false; } QString KisDuplicateOpSettings::indirectPaintingCompositeOp() const { return COMPOSITE_COPY; } QPointF KisDuplicateOpSettings::offset() const { return m_offset; } QPointF KisDuplicateOpSettings::position() const { return m_position; } bool KisDuplicateOpSettings::mousePressEvent(const KisPaintInformation &info, Qt::KeyboardModifiers modifiers, KisNodeWSP currentNode) { bool ignoreEvent = true; if (modifiers & Qt::ControlModifier) { if (!m_sourceNode || !(modifiers & Qt::AltModifier)) { m_sourceNode = currentNode; } m_position = info.pos(); m_isOffsetNotUptodate = true; ignoreEvent = false; } else { if (m_isOffsetNotUptodate) { m_offset = info.pos() - m_position; m_isOffsetNotUptodate = false; } ignoreEvent = true; } return ignoreEvent; } KisNodeWSP KisDuplicateOpSettings::sourceNode() const { return m_sourceNode; } void KisDuplicateOpSettings::activate() { } void KisDuplicateOpSettings::fromXML(const QDomElement& elt) { // First, call the parent class fromXML to make sure all the // properties are saved to the map KisPaintOpSettings::fromXML(elt); m_offset.setX(KisDomUtils::toDouble(elt.attribute("OffsetX", "0.0"))); m_offset.setY(KisDomUtils::toDouble(elt.attribute("OffsetY", "0.0"))); m_isOffsetNotUptodate = false; } void KisDuplicateOpSettings::toXML(QDomDocument& doc, QDomElement& rootElt) const { // Then call the parent class fromXML KisPropertiesConfiguration::toXML(doc, rootElt); rootElt.setAttribute("OffsetX", QString::number(m_offset.x())); rootElt.setAttribute("OffsetY", QString::number(m_offset.y())); } KisPaintOpSettingsSP KisDuplicateOpSettings::clone() const { KisPaintOpSettingsSP setting = KisBrushBasedPaintOpSettings::clone(); KisDuplicateOpSettings* s = dynamic_cast(setting.data()); s->m_offset = m_offset; s->m_isOffsetNotUptodate = m_isOffsetNotUptodate; s->m_position = m_position; return setting; } QPainterPath KisDuplicateOpSettings::brushOutline(const KisPaintInformation &info, const OutlineMode &mode) { QPainterPath path; OutlineMode forcedMode = mode; if (!forcedMode.isVisible) { forcedMode.isVisible = true; forcedMode.forceCircle = true; } // clone tool should always show an outline path = KisBrushBasedPaintOpSettings::brushOutlineImpl(info, forcedMode, 1.0); QPainterPath copy(path); QRectF rect2 = copy.boundingRect(); if (m_isOffsetNotUptodate || !getBool(DUPLICATE_MOVE_SOURCE_POINT)) { copy.translate(m_position - info.pos()); } else { copy.translate(-m_offset); } path.addPath(copy); qreal dx = rect2.width() / 4.0; qreal dy = rect2.height() / 4.0; rect2.adjust(dx, dy, -dx, -dy); path.moveTo(rect2.topLeft()); path.lineTo(rect2.bottomRight()); path.moveTo(rect2.topRight()); path.lineTo(rect2.bottomLeft()); return path; } #include #include "kis_paintop_preset.h" #include "kis_paintop_settings_update_proxy.h" #include "kis_standard_uniform_properties_factory.h" QList KisDuplicateOpSettings::uniformProperties(KisPaintOpSettingsSP settings) { QList props = - listWeakToStrong(m_uniformProperties); + listWeakToStrong(m_uniformProperties); if (props.isEmpty()) { { KisUniformPaintOpPropertyCallback *prop = - new KisUniformPaintOpPropertyCallback( - KisUniformPaintOpPropertyCallback::Bool, - "clone_healing", - i18n("Healing"), - settings, 0); + new KisUniformPaintOpPropertyCallback( + KisUniformPaintOpPropertyCallback::Bool, + "clone_healing", + i18n("Healing"), + settings, 0); prop->setReadCallback( - [](KisUniformPaintOpProperty *prop) { - KisDuplicateOptionProperties option; - option.readOptionSetting(prop->settings().data()); + [](KisUniformPaintOpProperty *prop) { + KisDuplicateOptionProperties option; + option.readOptionSetting(prop->settings().data()); - prop->setValue(option.duplicate_healing); - }); + prop->setValue(option.duplicate_healing); + }); prop->setWriteCallback( - [](KisUniformPaintOpProperty *prop) { - KisDuplicateOptionProperties option; - option.readOptionSetting(prop->settings().data()); - option.duplicate_healing = prop->value().toBool(); - option.writeOptionSetting(prop->settings().data()); - }); - - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + [](KisUniformPaintOpProperty *prop) { + KisDuplicateOptionProperties option; + option.readOptionSetting(prop->settings().data()); + option.duplicate_healing = prop->value().toBool(); + option.writeOptionSetting(prop->settings().data()); + }); + + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisUniformPaintOpPropertyCallback *prop = - new KisUniformPaintOpPropertyCallback( - KisUniformPaintOpPropertyCallback::Bool, - "clone_movesource", - i18n("Move Source"), - settings, 0); + new KisUniformPaintOpPropertyCallback( + KisUniformPaintOpPropertyCallback::Bool, + "clone_movesource", + i18n("Move `Source"), + settings, 0); prop->setReadCallback( - [](KisUniformPaintOpProperty *prop) { - KisDuplicateOptionProperties option; - option.readOptionSetting(prop->settings().data()); + [](KisUniformPaintOpProperty *prop) { + KisDuplicateOptionProperties option; + option.readOptionSetting(prop->settings().data()); - prop->setValue(option.duplicate_move_source_point); - }); + prop->setValue(option.duplicate_move_source_point); + }); prop->setWriteCallback( - [](KisUniformPaintOpProperty *prop) { - KisDuplicateOptionProperties option; - option.readOptionSetting(prop->settings().data()); - option.duplicate_move_source_point = prop->value().toBool(); - option.writeOptionSetting(prop->settings().data()); - }); - - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + [](KisUniformPaintOpProperty *prop) { + KisDuplicateOptionProperties option; + option.readOptionSetting(prop->settings().data()); + option.duplicate_move_source_point = prop->value().toBool(); + option.writeOptionSetting(prop->settings().data()); + }); + + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } } return KisPaintOpSettings::uniformProperties(settings) + props; } diff --git a/plugins/paintops/deform/kis_deform_paintop_settings.cpp b/plugins/paintops/deform/kis_deform_paintop_settings.cpp index f962a396f1..79d179a2e5 100644 --- a/plugins/paintops/deform/kis_deform_paintop_settings.cpp +++ b/plugins/paintops/deform/kis_deform_paintop_settings.cpp @@ -1,222 +1,225 @@ /* * Copyright (c) 2008,2009,2010 Lukáš Tvrdý * * 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 #include #include #include #include struct KisDeformPaintOpSettings::Private { QList uniformProperties; }; KisDeformPaintOpSettings::KisDeformPaintOpSettings() : KisOutlineGenerationPolicy(KisCurrentOutlineFetcher::SIZE_OPTION | KisCurrentOutlineFetcher::ROTATION_OPTION), m_d(new Private) { } KisDeformPaintOpSettings::~KisDeformPaintOpSettings() { } void KisDeformPaintOpSettings::setPaintOpSize(qreal value) { KisBrushSizeOptionProperties option; option.readOptionSetting(this); option.brush_diameter = value; option.writeOptionSetting(this); } qreal KisDeformPaintOpSettings::paintOpSize() const { KisBrushSizeOptionProperties option; option.readOptionSetting(this); return option.brush_diameter; } bool KisDeformPaintOpSettings::paintIncremental() { return true; } bool KisDeformPaintOpSettings::isAirbrushing() const { // version 2.3 if (hasProperty(AIRBRUSH_ENABLED)) { return getBool(AIRBRUSH_ENABLED); } else { return getBool(DEFORM_USE_MOVEMENT_PAINT); } } QPainterPath KisDeformPaintOpSettings::brushOutline(const KisPaintInformation &info, const OutlineMode &mode) { QPainterPath path; if (mode.isVisible) { qreal width = getInt(BRUSH_DIAMETER); qreal height = getInt(BRUSH_DIAMETER) * getDouble(BRUSH_ASPECT); path = ellipseOutline(width, height, getDouble(BRUSH_SCALE), getDouble(BRUSH_ROTATION)); path = outlineFetcher()->fetchOutline(info, this, path, mode); if (mode.showTiltDecoration) { QPainterPath tiltLine = makeTiltIndicator(info, QPointF(0.0, 0.0), width * 0.5, 3.0); path.addPath(outlineFetcher()->fetchOutline(info, this, tiltLine, mode, 1.0, 0.0, true, 0, 0)); } } return path; } #include #include #include "kis_paintop_preset.h" #include "kis_paintop_settings_update_proxy.h" #include "kis_standard_uniform_properties_factory.h" QList KisDeformPaintOpSettings::uniformProperties(KisPaintOpSettingsSP settings) { QList props = listWeakToStrong(m_d->uniformProperties); if (props.isEmpty()) { { KisDoubleSliderBasedPaintOpPropertyCallback *prop = new KisDoubleSliderBasedPaintOpPropertyCallback( KisDoubleSliderBasedPaintOpPropertyCallback::Double, "deform_amount", i18n("Amount"), settings, 0); prop->setRange(0.01, 1.0); prop->setSingleStep(0.01); prop->setDecimals(2); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { DeformOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.deform_amount); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { DeformOption option; option.readOptionSetting(prop->settings().data()); option.deform_amount = prop->value().toReal(); option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisComboBasedPaintOpPropertyCallback *prop = new KisComboBasedPaintOpPropertyCallback( "deform_mode", i18n("Deform Mode"), settings, 0); QList modes; modes << i18n("Grow"); modes << i18n("Shrink"); modes << i18n("Swirl CW"); modes << i18n("Swirl CCW"); modes << i18n("Move"); modes << i18n("Lens Zoom In"); modes << i18n("Lens Zoom Out"); modes << i18n("Color Deformation"); prop->setItems(modes); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { DeformOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(int(option.deform_action - 1)); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { DeformOption option; option.readOptionSetting(prop->settings().data()); option.deform_action = prop->value().toInt() + 1; option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisIntSliderBasedPaintOpPropertyCallback *prop = new KisIntSliderBasedPaintOpPropertyCallback( KisIntSliderBasedPaintOpPropertyCallback::Int, "deform_angle", i18n("Angle"), settings, 0); const QString degree = QChar(Qt::Key_degree); prop->setRange(0, 360); prop->setSingleStep(1); prop->setSuffix(degree); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { KisBrushSizeOptionProperties option; option.readOptionSetting(prop->settings().data()); prop->setValue(int(option.brush_rotation)); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { KisBrushSizeOptionProperties option; option.readOptionSetting(prop->settings().data()); option.brush_rotation = prop->value().toInt(); option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } } { using namespace KisStandardUniformPropertiesFactory; Q_FOREACH (KisUniformPaintOpPropertySP prop, KisPaintOpSettings::uniformProperties(settings)) { if (prop->id() == opacity.id() || prop->id() == size.id()) { props.prepend(prop); } } } return props; } diff --git a/plugins/paintops/experiment/kis_experiment_paintop_settings.cpp b/plugins/paintops/experiment/kis_experiment_paintop_settings.cpp index 8aba8ac662..b755645550 100644 --- a/plugins/paintops/experiment/kis_experiment_paintop_settings.cpp +++ b/plugins/paintops/experiment/kis_experiment_paintop_settings.cpp @@ -1,265 +1,270 @@ /* * Copyright (c) 2009,2010 Lukáš Tvrdý * * 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_experiment_paintop_settings.h" #include "kis_current_outline_fetcher.h" struct KisExperimentPaintOpSettings::Private { QList uniformProperties; }; KisExperimentPaintOpSettings::KisExperimentPaintOpSettings() : m_d(new Private) { } KisExperimentPaintOpSettings::~KisExperimentPaintOpSettings() { } bool KisExperimentPaintOpSettings::lodSizeThresholdSupported() const { return false; } bool KisExperimentPaintOpSettings::paintIncremental() { /** * The experiment brush supports working in the * WASH mode only! */ return false; } QPainterPath KisExperimentPaintOpSettings::brushOutline(const KisPaintInformation &info, const OutlineMode &mode) { QPainterPath path; if (mode.isVisible) { QRectF ellipse(0, 0, 3, 3); ellipse.translate(-ellipse.center()); path.addEllipse(ellipse); ellipse.setRect(0,0, 12, 12); ellipse.translate(-ellipse.center()); path.addEllipse(ellipse); if (mode.showTiltDecoration) { path.addPath(makeTiltIndicator(info, QPointF(0.0, 0.0), 0.0, 3.0)); } path.translate(info.pos()); } return path; } #include #include "kis_paintop_preset.h" #include "kis_paintop_settings_update_proxy.h" #include "kis_experimentop_option.h" #include "kis_standard_uniform_properties_factory.h" QList KisExperimentPaintOpSettings::uniformProperties(KisPaintOpSettingsSP settings) { QList props = listWeakToStrong(m_d->uniformProperties); if (props.isEmpty()) { { KisIntSliderBasedPaintOpPropertyCallback *prop = new KisIntSliderBasedPaintOpPropertyCallback( KisIntSliderBasedPaintOpPropertyCallback::Int, "shape_speed", i18n("Speed"), settings, 0); prop->setRange(0, 100); prop->setSingleStep(1); prop->setSuffix(i18n("%")); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(int(option.speed)); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); option.speed = prop->value().toInt(); option.writeOptionSetting(prop->settings().data()); }); prop->setIsVisibleCallback( [](const KisUniformPaintOpProperty *prop) -> bool { ExperimentOption option; option.readOptionSetting(prop->settings().data()); return option.isSpeedEnabled; }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisIntSliderBasedPaintOpPropertyCallback *prop = new KisIntSliderBasedPaintOpPropertyCallback( KisIntSliderBasedPaintOpPropertyCallback::Int, "shape_smooth", i18n("Smooth"), settings, 0); prop->setRange(0, 100); prop->setSingleStep(1); prop->setSuffix(i18n(" px")); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(int(option.smoothing)); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); option.smoothing = prop->value().toInt(); option.writeOptionSetting(prop->settings().data()); }); prop->setIsVisibleCallback( [](const KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); return option.isSmoothingEnabled; }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisIntSliderBasedPaintOpPropertyCallback *prop = new KisIntSliderBasedPaintOpPropertyCallback( KisIntSliderBasedPaintOpPropertyCallback::Int, "shape_displace", i18n("Displace"), settings, 0); prop->setRange(0, 100); prop->setSingleStep(1); prop->setSuffix(i18n("%")); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(int(option.displacement)); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); option.displacement = prop->value().toInt(); option.writeOptionSetting(prop->settings().data()); }); prop->setIsVisibleCallback( [](const KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); return option.isDisplacementEnabled; }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisUniformPaintOpPropertyCallback *prop = new KisUniformPaintOpPropertyCallback( KisUniformPaintOpPropertyCallback::Bool, "shape_windingfill", i18n("Winding Fill"), settings, 0); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.windingFill); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); option.windingFill = prop->value().toBool(); option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisUniformPaintOpPropertyCallback *prop = new KisUniformPaintOpPropertyCallback( KisUniformPaintOpPropertyCallback::Bool, "shape_hardedge", i18n("Hard Edge"), settings, 0); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.hardEdge); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { ExperimentOption option; option.readOptionSetting(prop->settings().data()); option.hardEdge = prop->value().toBool(); option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } } { using namespace KisStandardUniformPropertiesFactory; Q_FOREACH (KisUniformPaintOpPropertySP prop, KisPaintOpSettings::uniformProperties(settings)) { if (prop->id() == opacity.id()) { props.prepend(prop); } } } return props; } diff --git a/plugins/paintops/gridbrush/kis_grid_paintop_settings.cpp b/plugins/paintops/gridbrush/kis_grid_paintop_settings.cpp index 346d6936e8..9a6ba70dc4 100644 --- a/plugins/paintops/gridbrush/kis_grid_paintop_settings.cpp +++ b/plugins/paintops/gridbrush/kis_grid_paintop_settings.cpp @@ -1,129 +1,130 @@ /* * Copyright (c) 2009,2010 Lukáš Tvrdý (lukast.dev@gmail.com) * * 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 #include "kis_grid_paintop_settings.h" #include "kis_grid_paintop_settings_widget.h" #include "kis_gridop_option.h" #include "kis_grid_shape_option.h" #include struct KisGridPaintOpSettings::Private { QList uniformProperties; }; KisGridPaintOpSettings::KisGridPaintOpSettings() : KisOutlineGenerationPolicy(KisCurrentOutlineFetcher::NO_OPTION), m_d(new Private) { } void KisGridPaintOpSettings::setPaintOpSize(qreal value) { KisGridOpProperties option; option.readOptionSetting(this); option.grid_width = value; option.grid_height = value; option.writeOptionSetting(this); } qreal KisGridPaintOpSettings::paintOpSize() const { KisGridOpProperties option; option.readOptionSetting(this); return option.grid_width; } KisGridPaintOpSettings::~KisGridPaintOpSettings() { } bool KisGridPaintOpSettings::paintIncremental() { return (enumPaintActionType)getInt("PaintOpAction", WASH) == BUILDUP; } QPainterPath KisGridPaintOpSettings::brushOutline(const KisPaintInformation &info, const OutlineMode &mode) { QPainterPath path; if (mode.isVisible) { qreal sizex = getInt(GRID_WIDTH) * getDouble(GRID_SCALE); qreal sizey = getInt(GRID_HEIGHT) * getDouble(GRID_SCALE); QRectF rc(0, 0, sizex, sizey); rc.translate(-rc.center()); path.addRect(rc); path = outlineFetcher()->fetchOutline(info, this, path, mode); if (mode.showTiltDecoration) { QPainterPath tiltLine = makeTiltIndicator(info, QPointF(0.0, 0.0), sizex * 0.5, 3.0); path.addPath(outlineFetcher()->fetchOutline(info, this, tiltLine, mode, 1.0, 0.0, true, 0, 0)); } } return path; } #include #include "kis_paintop_preset.h" #include "kis_paintop_settings_update_proxy.h" QList KisGridPaintOpSettings::uniformProperties(KisPaintOpSettingsSP settings) { QList props = listWeakToStrong(m_d->uniformProperties); if (props.isEmpty()) { { KisIntSliderBasedPaintOpPropertyCallback *prop = new KisIntSliderBasedPaintOpPropertyCallback( KisIntSliderBasedPaintOpPropertyCallback::Int, "grid_divisionlevel", i18n("Division Level"), settings, 0); prop->setRange(1, 25); prop->setSingleStep(1); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { KisGridOpProperties option; option.readOptionSetting(prop->settings().data()); prop->setValue(int(option.grid_division_level)); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { KisGridOpProperties option; option.readOptionSetting(prop->settings().data()); option.grid_division_level = prop->value().toInt(); option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } } return KisPaintOpSettings::uniformProperties(settings) + props; } diff --git a/plugins/paintops/hatching/kis_hatching_paintop_settings.cpp b/plugins/paintops/hatching/kis_hatching_paintop_settings.cpp index 362ae1acb9..fd4af7b213 100644 --- a/plugins/paintops/hatching/kis_hatching_paintop_settings.cpp +++ b/plugins/paintops/hatching/kis_hatching_paintop_settings.cpp @@ -1,220 +1,223 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2010 José Luis Vergara * * 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_hatching_paintop_settings.h" #include #include #include const QString HATCHING_VERSION = "Hatching/Version"; struct KisHatchingPaintOpSettings::Private { QList uniformProperties; }; KisHatchingPaintOpSettings::KisHatchingPaintOpSettings() : m_d(new Private) { setProperty(HATCHING_VERSION, "2"); } KisHatchingPaintOpSettings::~KisHatchingPaintOpSettings() { } void KisHatchingPaintOpSettings::initializeTwin(KisPaintOpSettingsSP settings) const { // XXX: this is a nice way to reinvent the copy constructor? /*--------DO NOT REMOVE please, use this to review the XML config tree QMap rofl = QMap(getProperties()); QMap::const_iterator i; for (i = rofl.constBegin(); i != rofl.constEnd(); ++i) dbgKrita << i.key() << ":" << i.value(); /----------DO NOT REMOVE----------------*/ KisHatchingPaintOpSettings *convenienttwin = static_cast(settings.data()); convenienttwin->enabledcurveangle = getBool("PressureAngle"); convenienttwin->enabledcurvecrosshatching = getBool("PressureCrosshatching"); convenienttwin->enabledcurveopacity = getBool("PressureOpacity"); convenienttwin->enabledcurveseparation = getBool("PressureSeparation"); convenienttwin->enabledcurvesize = getBool("PressureSize"); convenienttwin->enabledcurvethickness = getBool("PressureThickness"); convenienttwin->angle = getDouble("Hatching/angle"); convenienttwin->separation = getDouble("Hatching/separation"); convenienttwin->thickness = getDouble("Hatching/thickness"); convenienttwin->origin_x = getDouble("Hatching/origin_x"); convenienttwin->origin_y = getDouble("Hatching/origin_y"); convenienttwin->nocrosshatching = getBool("Hatching/bool_nocrosshatching"); convenienttwin->perpendicular = getBool("Hatching/bool_perpendicular"); convenienttwin->minusthenplus = getBool("Hatching/bool_minusthenplus"); convenienttwin->plusthenminus = getBool("Hatching/bool_plusthenminus"); convenienttwin->moirepattern = getBool("Hatching/bool_moirepattern"); convenienttwin->separationintervals = getInt("Hatching/separationintervals"); //convenienttwin->trigonometryalgebra = getBool("Hatching/bool_trigonometryalgebra"); //convenienttwin->scratchoff = getBool("Hatching/bool_scratchoff"); convenienttwin->antialias = getBool("Hatching/bool_antialias"); convenienttwin->opaquebackground = getBool("Hatching/bool_opaquebackground"); convenienttwin->subpixelprecision = getBool("Hatching/bool_subpixelprecision"); if (getBool("Hatching/bool_nocrosshatching")) convenienttwin->crosshatchingstyle = 0; else if (getBool("Hatching/bool_perpendicular")) convenienttwin->crosshatchingstyle = 1; else if (getBool("Hatching/bool_minusthenplus")) convenienttwin->crosshatchingstyle = 2; else if (getBool("Hatching/bool_plusthenminus")) convenienttwin->crosshatchingstyle = 3; if (getBool("Hatching/bool_moirepattern")) convenienttwin->crosshatchingstyle = 4; } void KisHatchingPaintOpSettings::fromXML(const QDomElement& elt) { setProperty(HATCHING_VERSION, "1"); // This make sure that fromXML will override HAIRY_VERSION with 2, or will default to 1 KisBrushBasedPaintOpSettings::fromXML(elt); QVariant v; if (!getProperty(HATCHING_VERSION, v) || v == "1") { setProperty("Hatching/thickness", 2.0 * getDouble("Hatching/thickness")); } setProperty(HATCHING_VERSION, "2"); // make sure it's saved as version 2 next time } #include #include "kis_paintop_preset.h" #include "kis_paintop_settings_update_proxy.h" #include "kis_hatching_options.h" QList KisHatchingPaintOpSettings::uniformProperties(KisPaintOpSettingsSP settings) { QList props = listWeakToStrong(m_d->uniformProperties); if (props.isEmpty()) { { KisDoubleSliderBasedPaintOpPropertyCallback *prop = new KisDoubleSliderBasedPaintOpPropertyCallback( KisDoubleSliderBasedPaintOpPropertyCallback::Double, "hatching_angle", i18n("Hatching Angle"), settings, 0); const QString degree = QChar(Qt::Key_degree); prop->setRange(-90, 90); prop->setSingleStep(0.01); prop->setDecimals(2); prop->setSuffix(degree); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { HatchingOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.angle); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { HatchingOption option; option.readOptionSetting(prop->settings().data()); option.angle = prop->value().toReal(); option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisDoubleSliderBasedPaintOpPropertyCallback *prop = new KisDoubleSliderBasedPaintOpPropertyCallback( KisDoubleSliderBasedPaintOpPropertyCallback::Double, "hatching_separation", i18n("Separation"), settings, 0); prop->setRange(1.0, 30); prop->setSingleStep(0.01); prop->setDecimals(2); prop->setSuffix(i18n(" px")); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { HatchingOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.separation); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { HatchingOption option; option.readOptionSetting(prop->settings().data()); option.separation = prop->value().toReal(); option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisDoubleSliderBasedPaintOpPropertyCallback *prop = new KisDoubleSliderBasedPaintOpPropertyCallback( KisDoubleSliderBasedPaintOpPropertyCallback::Double, "hatching_thickness", i18n("Thickness"), settings, 0); prop->setRange(1.0, 30); prop->setSingleStep(0.01); prop->setDecimals(2); prop->setSuffix(i18n(" px")); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { HatchingOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.thickness); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { HatchingOption option; option.readOptionSetting(prop->settings().data()); option.thickness = prop->value().toReal(); option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } } return KisPaintOpSettings::uniformProperties(settings) + props; } diff --git a/plugins/paintops/libpaintop/KisDabCacheUtils.h b/plugins/paintops/libpaintop/KisDabCacheUtils.h index 6e694a08d3..aad40fad10 100644 --- a/plugins/paintops/libpaintop/KisDabCacheUtils.h +++ b/plugins/paintops/libpaintop/KisDabCacheUtils.h @@ -1,122 +1,122 @@ /* * Copyright (c) 2017 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. */ #ifndef KISDABCACHEUTILS_H #define KISDABCACHEUTILS_H #include #include #include "kis_types.h" #include #include "kis_dab_shape.h" #include "kritapaintop_export.h" #include class KisBrush; -typedef KisSharedPtr KisBrushSP; +typedef QSharedPointer KisBrushSP; class KisColorSource; class KisPressureSharpnessOption; class KisTextureProperties; namespace KisDabCacheUtils { struct PAINTOP_EXPORT DabRenderingResources { DabRenderingResources(); virtual ~DabRenderingResources(); virtual void syncResourcesToSeqNo(int seqNo, const KisPaintInformation &info); KisBrushSP brush; QScopedPointer colorSource; QScopedPointer sharpnessOption; QScopedPointer textureOption; KisPaintDeviceSP colorSourceDevice; private: DabRenderingResources(const DabRenderingResources &rhs) = delete; }; typedef std::function ResourcesFactory; struct PAINTOP_EXPORT DabRequestInfo { DabRequestInfo(const KoColor &_color, const QPointF &_cursorPoint, const KisDabShape &_shape, const KisPaintInformation &_info, qreal _softnessFactor) : color(_color), cursorPoint(_cursorPoint), shape(_shape), info(_info), softnessFactor(_softnessFactor) { } const KoColor &color; const QPointF &cursorPoint; const KisDabShape &shape; const KisPaintInformation &info; const qreal softnessFactor; private: DabRequestInfo(const DabRequestInfo &rhs); }; struct PAINTOP_EXPORT DabGenerationInfo { MirrorProperties mirrorProperties; KisDabShape shape; QRect dstDabRect; QPointF subPixel; bool solidColorFill = true; KoColor paintColor; KisPaintInformation info; qreal softnessFactor = 1.0; bool needsPostprocessing = false; }; PAINTOP_EXPORT QRect correctDabRectWhenFetchedFromCache(const QRect &dabRect, const QSize &realDabSize); PAINTOP_EXPORT void generateDab(const DabGenerationInfo &di, DabRenderingResources *resources, KisFixedPaintDeviceSP *dab); PAINTOP_EXPORT void postProcessDab(KisFixedPaintDeviceSP dab, const QPoint &dabTopLeft, const KisPaintInformation& info, DabRenderingResources *resources); } template class QSharedPointer; class KisDabRenderingJob; typedef QSharedPointer KisDabRenderingJobSP; #endif // KISDABCACHEUTILS_H diff --git a/plugins/paintops/libpaintop/KisMaskingBrushOptionProperties.h b/plugins/paintops/libpaintop/KisMaskingBrushOptionProperties.h index 8ad9ff1a1a..8258761540 100644 --- a/plugins/paintops/libpaintop/KisMaskingBrushOptionProperties.h +++ b/plugins/paintops/libpaintop/KisMaskingBrushOptionProperties.h @@ -1,42 +1,39 @@ /* * Copyright (c) 2017 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. */ #ifndef KISMASKINGBRUSHOPTIONPROPERTIES_H #define KISMASKINGBRUSHOPTIONPROPERTIES_H #include "kritapaintop_export.h" #include - - -class KisBrush; -typedef KisSharedPtr KisBrushSP; +#include struct PAINTOP_EXPORT KisMaskingBrushOptionProperties { KisMaskingBrushOptionProperties(); bool isEnabled = false; KisBrushSP brush; QString compositeOpId; bool useMasterSize = true; void write(KisPropertiesConfiguration *setting, qreal masterBrushSize) const; void read(const KisPropertiesConfiguration *setting, qreal masterBrushSize); }; #endif // KISMASKINGBRUSHOPTIONPROPERTIES_H diff --git a/plugins/paintops/libpaintop/KisTextureMaskInfo.h b/plugins/paintops/libpaintop/KisTextureMaskInfo.h index 9ac1834388..60096a7563 100644 --- a/plugins/paintops/libpaintop/KisTextureMaskInfo.h +++ b/plugins/paintops/libpaintop/KisTextureMaskInfo.h @@ -1,89 +1,90 @@ /* * Copyright (c) 2017 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. */ #ifndef KISTEXTUREMASKINFO_H #define KISTEXTUREMASKINFO_H #include #include #include #include -class KoPattern; +#include + class KisTextureMaskInfo; class KisTextureMaskInfo : public boost::equality_comparable { public: KisTextureMaskInfo(int levelOfDetail); KisTextureMaskInfo(const KisTextureMaskInfo &rhs); ~KisTextureMaskInfo(); friend bool operator==(const KisTextureMaskInfo &lhs, const KisTextureMaskInfo &rhs); KisTextureMaskInfo& operator=(const KisTextureMaskInfo &rhs); int levelOfDetail() const; bool hasMask() const; KisPaintDeviceSP mask(); QRect maskBounds() const; bool fillProperties(const KisPropertiesConfigurationSP setting); void recalculateMask(); private: int m_levelOfDetail = 0; - KoPattern *m_pattern = 0; + KoPatternSP m_pattern = 0; qreal m_scale = 1.0; qreal m_brightness = 0.0; qreal m_contrast = 1.0; bool m_invert = false; int m_cutoffLeft = 0; int m_cutoffRight = 255; int m_cutoffPolicy = 0; KisPaintDeviceSP m_mask; QRect m_maskBounds; }; typedef QSharedPointer KisTextureMaskInfoSP; struct KisTextureMaskInfoCache { static KisTextureMaskInfoCache *instance(); KisTextureMaskInfoSP fetchCachedTextureInfo(KisTextureMaskInfoSP info); private: QMutex m_mutex; QSharedPointer m_lodInfo; QSharedPointer m_mainInfo; }; #endif // KISTEXTUREMASKINFO_H diff --git a/plugins/paintops/libpaintop/kis_auto_brush_widget.cpp b/plugins/paintops/libpaintop/kis_auto_brush_widget.cpp index 8785178082..52edb0defd 100644 --- a/plugins/paintops/libpaintop/kis_auto_brush_widget.cpp +++ b/plugins/paintops/libpaintop/kis_auto_brush_widget.cpp @@ -1,295 +1,295 @@ /* * Copyright (c) 2004,2007,2009 Cyrille Berger * Copyright (c) 2010 Lukáš Tvrdý * * 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 //MSVC requires that Vc come first #include "kis_auto_brush_widget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_signals_blocker.h" #include "kis_signal_compressor.h" #include "kis_aspect_ratio_locker.h" #define showSlider(input, step) input->setRange(input->minimum(), input->maximum(), step) #include KisAutoBrushWidget::KisAutoBrushWidget(QWidget *parent, const char* name) : KisWdgAutoBrush(parent, name) , m_autoBrush(0) , m_updateCompressor(new KisSignalCompressor(100, KisSignalCompressor::FIRST_ACTIVE)) , m_fadeAspectLocker(new KisAspectRatioLocker()) { connect(m_updateCompressor.data(), SIGNAL(timeout()), SLOT(paramChanged())); connect((QObject*)comboBoxShape, SIGNAL(activated(int)), m_updateCompressor.data(), SLOT(start())); inputRadius->setRange(0, KSharedConfig::openConfig()->group("").readEntry("maximumBrushSize", 1000), 2); inputRadius->setExponentRatio(3.0); inputRadius->setSingleStep(1); inputRadius->setValue(5); inputRadius->setSuffix(i18n(" px")); inputRadius->setBlockUpdateSignalOnDrag(true); connect(inputRadius, SIGNAL(valueChanged(qreal)), m_updateCompressor.data(), SLOT(start())); inputRatio->setRange(0.0, 1.0, 2); inputRatio->setSingleStep(0.1); inputRatio->setValue(1.0); inputRatio->setBlockUpdateSignalOnDrag(true); connect(inputRatio, SIGNAL(valueChanged(qreal)), m_updateCompressor.data(), SLOT(start())); inputHFade->setRange(0.0, 1.0, 2); inputHFade->setSingleStep(0.1); inputHFade->setValue(0.5); inputVFade->setRange(0.0, 1.0, 2); inputVFade->setSingleStep(0.1); inputVFade->setValue(0.5); aspectButton->setKeepAspectRatio(true); m_fadeAspectLocker->connectSpinBoxes(inputHFade, inputVFade, aspectButton); m_fadeAspectLocker->setBlockUpdateSignalOnDrag(true); connect(m_fadeAspectLocker.data(), SIGNAL(sliderValueChanged()), m_updateCompressor.data(), SLOT(start())); connect(m_fadeAspectLocker.data(), SIGNAL(aspectButtonChanged()), m_updateCompressor.data(), SLOT(start())); inputSpikes->setRange(2, 20); inputSpikes->setValue(2); inputSpikes->setBlockUpdateSignalOnDrag(true); connect(inputSpikes, SIGNAL(valueChanged(int)), m_updateCompressor.data(), SLOT(start())); inputRandomness->setRange(0, 100); inputRandomness->setValue(0); inputRandomness->setBlockUpdateSignalOnDrag(true); connect(inputRandomness, SIGNAL(valueChanged(qreal)), m_updateCompressor.data(), SLOT(start())); inputAngle->setRange(0, 360); inputAngle->setSuffix(QChar(Qt::Key_degree)); inputAngle->setValue(0); inputAngle->setBlockUpdateSignalOnDrag(true); connect(inputAngle, SIGNAL(valueChanged(int)), m_updateCompressor.data(), SLOT(start())); connect(spacingWidget, SIGNAL(sigSpacingChanged()), m_updateCompressor.data(), SLOT(start())); density->setRange(0, 100, 0); density->setSingleStep(1); density->setValue(100); density->setSuffix("%"); density->setBlockUpdateSignalOnDrag(true); connect(density, SIGNAL(valueChanged(qreal)), m_updateCompressor.data(), SLOT(start())); KisCubicCurve topLeftBottomRightLinearCurve; topLeftBottomRightLinearCurve.setPoint(0, QPointF(0.0, 1.0)); topLeftBottomRightLinearCurve.setPoint(1, QPointF(1.0, 0.0)); softnessCurve->setCurve(topLeftBottomRightLinearCurve); connect(softnessCurve, SIGNAL(modified()), m_updateCompressor.data(), SLOT(start())); m_brush = QImage(1, 1, QImage::Format_RGB32); connect(brushPreview, SIGNAL(clicked()), m_updateCompressor.data(), SLOT(start())); QList ids = KisMaskGenerator::maskGeneratorIds(); for (int i = 0; i < ids.size(); i++) { comboBoxMaskType->insertItem(i, ids[i].name()); } connect(comboBoxMaskType, SIGNAL(activated(int)), m_updateCompressor.data(), SLOT(start())); connect(comboBoxMaskType, SIGNAL(currentIndexChanged(int)), SLOT(setStackedWidget(int))); setStackedWidget(comboBoxMaskType->currentIndex()); brushPreview->setIconSize(QSize(100, 100)); connect(btnAntialiasing, SIGNAL(toggled(bool)), m_updateCompressor.data(), SLOT(start())); m_updateCompressor->start(); } KisAutoBrushWidget::~KisAutoBrushWidget() { } void KisAutoBrushWidget::resizeEvent(QResizeEvent *) { brushPreview->setMinimumHeight(brushPreview->width()); // dirty hack ! brushPreview->setMaximumHeight(brushPreview->width()); // dirty hack ! } void KisAutoBrushWidget::activate() { m_updateCompressor->start(); } void KisAutoBrushWidget::paramChanged() { KisMaskGenerator* kas; bool antialiasEdges = btnAntialiasing->isChecked(); if (comboBoxMaskType->currentIndex() == 2) { // gaussian brush if (comboBoxShape->currentIndex() == 0) { kas = new KisGaussCircleMaskGenerator(inputRadius->value(), inputRatio->value(), inputHFade->value(), inputVFade->value(), inputSpikes->value(), antialiasEdges); } else { kas = new KisGaussRectangleMaskGenerator(inputRadius->value(), inputRatio->value(), inputHFade->value(), inputVFade->value(), inputSpikes->value(), antialiasEdges); } } else if (comboBoxMaskType->currentIndex() == 1) { // soft brush if (comboBoxShape->currentIndex() == 0) { kas = new KisCurveCircleMaskGenerator(inputRadius->value(), inputRatio->value(), inputHFade->value(), inputVFade->value(), inputSpikes->value(), softnessCurve->curve(), antialiasEdges); } else { kas = new KisCurveRectangleMaskGenerator(inputRadius->value(), inputRatio->value(), inputHFade->value(), inputVFade->value(), inputSpikes->value(), softnessCurve->curve(), antialiasEdges); } } else {// default == 0 or any other if (comboBoxShape->currentIndex() == 0) { // use index compare instead of comparing a translatable string kas = new KisCircleMaskGenerator(inputRadius->value(), inputRatio->value(), inputHFade->value(), inputVFade->value(), inputSpikes->value(), antialiasEdges); } else { kas = new KisRectangleMaskGenerator(inputRadius->value(), inputRatio->value(), inputHFade->value(), inputVFade->value(), inputSpikes->value(), antialiasEdges); } } Q_CHECK_PTR(kas); - m_autoBrush = new KisAutoBrush(kas, inputAngle->value() / 180.0 * M_PI, inputRandomness->value() / 100.0, density->value() / 100.0); + m_autoBrush = KisBrushSP(new KisAutoBrush(kas, inputAngle->value() / 180.0 * M_PI, inputRandomness->value() / 100.0, density->value() / 100.0)); m_autoBrush->setSpacing(spacingWidget->spacing()); m_autoBrush->setAutoSpacing(spacingWidget->autoSpacingActive(), spacingWidget->autoSpacingCoeff()); m_brush = m_autoBrush->image(); drawBrushPreviewArea(); emit sigBrushChanged(); } void KisAutoBrushWidget::drawBrushPreviewArea() { QImage pi(m_brush); double coeff = 1.0; int bPw = brushPreview->width() - 3; if (pi.width() > bPw) { coeff = bPw / (double)pi.width(); } int bPh = brushPreview->height() - 3; if (pi.height() > coeff * bPh) { coeff = bPh / (double)pi.height(); } if (coeff < 1.0) { pi = pi.scaled((int)(coeff * pi.width()) , (int)(coeff * pi.height()), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } QPixmap p = QPixmap::fromImage(pi); brushPreview->setIcon(QIcon(p)); } void KisAutoBrushWidget::setStackedWidget(int index) { if (index == 1) { stackedWidget->setCurrentIndex(1); } else { stackedWidget->setCurrentIndex(0); } } KisBrushSP KisAutoBrushWidget::brush() { return m_autoBrush; } void KisAutoBrushWidget::setBrush(KisBrushSP brush) { m_autoBrush = brush; m_brush = brush->image(); // XXX: lock, set and unlock the widgets. KisAutoBrush* aBrush = dynamic_cast(brush.data()); KisSignalsBlocker b1(comboBoxShape, comboBoxMaskType); KisSignalsBlocker b2(inputRadius, inputRatio, inputHFade, inputVFade, inputAngle, inputSpikes); KisSignalsBlocker b3(spacingWidget, inputRandomness, density, softnessCurve, btnAntialiasing); if (aBrush->maskGenerator()->type() == KisMaskGenerator::CIRCLE) { comboBoxShape->setCurrentIndex(0); } else if (aBrush->maskGenerator()->type() == KisMaskGenerator::RECTANGLE) { comboBoxShape->setCurrentIndex(1); } else { comboBoxShape->setCurrentIndex(2); } const int mastTypeIndex = comboBoxMaskType->findText(aBrush->maskGenerator()->name()); comboBoxMaskType->setCurrentIndex(mastTypeIndex); setStackedWidget(mastTypeIndex); // adjusting manually because the signals are blocked inputRadius->setValue(aBrush->maskGenerator()->diameter()); inputRatio->setValue(aBrush->maskGenerator()->ratio()); inputHFade->setValue(aBrush->maskGenerator()->horizontalFade()); inputVFade->setValue(aBrush->maskGenerator()->verticalFade()); inputAngle->setValue(aBrush->angle() * 180 / M_PI); inputSpikes->setValue(aBrush->maskGenerator()->spikes()); spacingWidget->setSpacing(aBrush->autoSpacingActive(), aBrush->autoSpacingActive() ? aBrush->autoSpacingCoeff() : aBrush->spacing()); inputRandomness->setValue(aBrush->randomness() * 100); density->setValue(aBrush->density() * 100); if (!aBrush->maskGenerator()->curveString().isEmpty()) { KisCubicCurve curve; curve.fromString(aBrush->maskGenerator()->curveString()); softnessCurve->setCurve(curve); } btnAntialiasing->setChecked(aBrush->maskGenerator()->antialiasEdges()); drawBrushPreviewArea(); // sync up what the brush preview area looks like } void KisAutoBrushWidget::setBrushSize(qreal dxPixels, qreal dyPixels) { Q_UNUSED(dyPixels); qreal newWidth = inputRadius->value() + dxPixels; newWidth = qMax(newWidth, qreal(0.1)); inputRadius->setValue(newWidth); } QSizeF KisAutoBrushWidget::brushSize() const { return QSizeF(inputRadius->value(), inputRadius->value() * inputRatio->value()); } #include "moc_kis_auto_brush_widget.cpp" diff --git a/plugins/paintops/libpaintop/kis_brush_based_paintop_settings.cpp b/plugins/paintops/libpaintop/kis_brush_based_paintop_settings.cpp index 49a8ddfb3a..1d39e5696d 100644 --- a/plugins/paintops/libpaintop/kis_brush_based_paintop_settings.cpp +++ b/plugins/paintops/libpaintop/kis_brush_based_paintop_settings.cpp @@ -1,334 +1,338 @@ /* * Copyright (c) 2010 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_brush_based_paintop_settings.h" #include #include #include "kis_brush_based_paintop_options_widget.h" #include #include "kis_brush_server.h" #include #include "kis_signals_blocker.h" #include "kis_brush_option.h" #include +#include struct BrushReader { BrushReader(const KisBrushBasedPaintOpSettings *parent) : m_parent(parent) { m_option.readOptionSetting(m_parent); } KisBrushSP brush() { return m_option.brush(); } const KisBrushBasedPaintOpSettings *m_parent; KisBrushOptionProperties m_option; }; struct BrushWriter { BrushWriter(KisBrushBasedPaintOpSettings *parent) : m_parent(parent) { m_option.readOptionSetting(m_parent); } ~BrushWriter() { m_option.writeOptionSetting(m_parent); } KisBrushSP brush() { return m_option.brush(); } KisBrushBasedPaintOpSettings *m_parent; KisBrushOptionProperties m_option; }; KisBrushBasedPaintOpSettings::KisBrushBasedPaintOpSettings() : KisOutlineGenerationPolicy(KisCurrentOutlineFetcher::SIZE_OPTION | KisCurrentOutlineFetcher::ROTATION_OPTION | KisCurrentOutlineFetcher::MIRROR_OPTION) { } bool KisBrushBasedPaintOpSettings::paintIncremental() { if (hasProperty("PaintOpAction")) { return (enumPaintActionType)getInt("PaintOpAction", WASH) == BUILDUP; } return true; } KisPaintOpSettingsSP KisBrushBasedPaintOpSettings::clone() const { KisPaintOpSettingsSP _settings = KisOutlineGenerationPolicy::clone(); KisBrushBasedPaintOpSettingsSP settings = dynamic_cast(_settings.data()); settings->m_savedBrush = 0; return settings; } KisBrushSP KisBrushBasedPaintOpSettings::brush() const { KisBrushSP brush = m_savedBrush; if (!brush) { BrushReader w(this); brush = w.brush(); m_savedBrush = brush; } return brush; } QPainterPath KisBrushBasedPaintOpSettings::brushOutlineImpl(const KisPaintInformation &info, const OutlineMode &mode, qreal additionalScale) { QPainterPath path; if (mode.isVisible) { KisBrushSP brush = this->brush(); if (!brush) return path; qreal finalScale = brush->scale() * additionalScale; QPainterPath realOutline = brush->outline(); if (mode.forceCircle) { QPainterPath ellipse; ellipse.addEllipse(realOutline.boundingRect()); realOutline = ellipse; } path = outlineFetcher()->fetchOutline(info, this, realOutline, mode, finalScale, brush->angle()); if (mode.showTiltDecoration) { const QPainterPath tiltLine = makeTiltIndicator(info, realOutline.boundingRect().center(), realOutline.boundingRect().width() * 0.5, 3.0); path.addPath(outlineFetcher()->fetchOutline(info, this, tiltLine, mode, finalScale, 0.0, true, realOutline.boundingRect().center().x(), realOutline.boundingRect().center().y())); } } return path; } QPainterPath KisBrushBasedPaintOpSettings::brushOutline(const KisPaintInformation &info, const OutlineMode &mode) { return brushOutlineImpl(info, mode, 1.0); } bool KisBrushBasedPaintOpSettings::isValid() const { QStringList files = getStringList(KisPaintOpUtils::RequiredBrushFilesListTag); files << getString(KisPaintOpUtils::RequiredBrushFileTag); Q_FOREACH (const QString &file, files) { if (!file.isEmpty()) { KisBrushSP brush = KisBrushServer::instance()->brushServer()->resourceByFilename(file); if (!brush) { return false; } } } return true; } bool KisBrushBasedPaintOpSettings::isLoadable() { return (KisBrushServer::instance()->brushServer()->resources().count() > 0); } void KisBrushBasedPaintOpSettings::setAngle(qreal value) { BrushWriter w(this); if (!w.brush()) return; w.brush()->setAngle(value); } qreal KisBrushBasedPaintOpSettings::angle() { return this->brush()->angle(); } void KisBrushBasedPaintOpSettings::setSpacing(qreal value) { BrushWriter w(this); if (!w.brush()) return; w.brush()->setSpacing(value); } qreal KisBrushBasedPaintOpSettings::spacing() { return this->brush()->spacing(); } void KisBrushBasedPaintOpSettings::setAutoSpacing(bool active, qreal coeff) { BrushWriter w(this); if (!w.brush()) return; w.brush()->setAutoSpacing(active, coeff); } bool KisBrushBasedPaintOpSettings::autoSpacingActive() { return this->brush()->autoSpacingActive(); } qreal KisBrushBasedPaintOpSettings::autoSpacingCoeff() { return this->brush()->autoSpacingCoeff(); } void KisBrushBasedPaintOpSettings::setPaintOpSize(qreal value) { BrushWriter w(this); if (!w.brush()) return; w.brush()->setUserEffectiveSize(value); } qreal KisBrushBasedPaintOpSettings::paintOpSize() const { return this->brush()->userEffectiveSize(); } #include #include "kis_paintop_preset.h" #include "kis_paintop_settings_update_proxy.h" QList KisBrushBasedPaintOpSettings::uniformProperties(KisPaintOpSettingsSP settings) { QList props = listWeakToStrong(m_uniformProperties); if (props.isEmpty()) { { KisIntSliderBasedPaintOpPropertyCallback *prop = new KisIntSliderBasedPaintOpPropertyCallback( KisIntSliderBasedPaintOpPropertyCallback::Int, "angle", "Angle", settings, 0); prop->setRange(0, 360); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { KisBrushBasedPaintOpSettings *s = dynamic_cast(prop->settings().data()); const qreal angleResult = kisRadiansToDegrees(s->angle()); prop->setValue(angleResult); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { KisBrushBasedPaintOpSettings *s = dynamic_cast(prop->settings().data()); s->setAngle(kisDegreesToRadians(prop->value().toReal())); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisUniformPaintOpPropertyCallback *prop = new KisUniformPaintOpPropertyCallback( KisUniformPaintOpPropertyCallback::Bool, "auto_spacing", "Auto Spacing", settings, 0); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { KisBrushBasedPaintOpSettings *s = dynamic_cast(prop->settings().data()); prop->setValue(s->autoSpacingActive()); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { KisBrushBasedPaintOpSettings *s = dynamic_cast(prop->settings().data()); s->setAutoSpacing(prop->value().toBool(), s->autoSpacingCoeff()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisDoubleSliderBasedPaintOpPropertyCallback *prop = new KisDoubleSliderBasedPaintOpPropertyCallback( KisDoubleSliderBasedPaintOpPropertyCallback::Double, "spacing", "Spacing", settings, 0); prop->setRange(0.01, 10); prop->setSingleStep(0.01); prop->setExponentRatio(3.0); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { KisBrushBasedPaintOpSettings *s = dynamic_cast(prop->settings().data()); const qreal value = s->autoSpacingActive() ? s->autoSpacingCoeff() : s->spacing(); prop->setValue(value); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { KisBrushBasedPaintOpSettings *s = dynamic_cast(prop->settings().data()); if (s->autoSpacingActive()) { s->setAutoSpacing(true, prop->value().toReal()); } else { s->setSpacing(prop->value().toReal()); } }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } } return KisPaintOpSettings::uniformProperties(settings) + props; } void KisBrushBasedPaintOpSettings::onPropertyChanged() { m_savedBrush.clear(); KisOutlineGenerationPolicy::onPropertyChanged(); } diff --git a/plugins/paintops/libpaintop/kis_brush_chooser.cpp b/plugins/paintops/libpaintop/kis_brush_chooser.cpp index a391a0441f..1ed42fe83f 100644 --- a/plugins/paintops/libpaintop/kis_brush_chooser.cpp +++ b/plugins/paintops/libpaintop/kis_brush_chooser.cpp @@ -1,417 +1,417 @@ /* * Copyright (c) 2004 Adrian Page * Copyright (c) 2009 Sven Langkamp * Copyright (c) 2010 Cyrille Berger * Copyright (c) 2010 Lukáš Tvrdý * 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 "kis_brush_chooser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_brush_server.h" #include "widgets/kis_slider_spin_box.h" #include "widgets/kis_multipliers_double_slider_spinbox.h" #include "kis_spacing_selection_widget.h" #include "kis_signals_blocker.h" #include "kis_imagepipe_brush.h" #include "kis_custom_brush_widget.h" #include "kis_clipboard_brush_widget.h" #include #include "kis_global.h" #include "kis_gbr_brush.h" #include "kis_debug.h" #include "kis_image.h" /// The resource item delegate for rendering the resource preview class KisBrushDelegate : public QAbstractItemDelegate { public: KisBrushDelegate(QObject * parent = 0) : QAbstractItemDelegate(parent) {} ~KisBrushDelegate() override {} /// reimplemented void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const override; /// reimplemented QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex &) const override { return option.decorationSize; } }; void KisBrushDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const { if (! index.isValid()) return; - KisBrush *brush = static_cast(index.internalPointer()); + KisBrushSP brush = KisBrushSP(static_cast(index.internalPointer())); QRect itemRect = option.rect; QImage thumbnail = brush->image(); if (thumbnail.height() > itemRect.height() || thumbnail.width() > itemRect.width()) { thumbnail = thumbnail.scaled(itemRect.size() , Qt::KeepAspectRatio, Qt::SmoothTransformation); } painter->save(); int dx = (itemRect.width() - thumbnail.width()) / 2; int dy = (itemRect.height() - thumbnail.height()) / 2; painter->drawImage(itemRect.x() + dx, itemRect.y() + dy, thumbnail); if (option.state & QStyle::State_Selected) { painter->setPen(QPen(option.palette.highlight(), 2.0)); painter->drawRect(option.rect); painter->setCompositionMode(QPainter::CompositionMode_HardLight); painter->setOpacity(0.65); painter->fillRect(option.rect, option.palette.highlight()); } painter->restore(); } KisPredefinedBrushChooser::KisPredefinedBrushChooser(QWidget *parent, const char *name) : QWidget(parent), m_stampBrushWidget(0), m_clipboardBrushWidget(0) { setObjectName(name); setupUi(this); brushSizeSpinBox->setRange(0, KSharedConfig::openConfig()->group("").readEntry("maximumBrushSize", 1000), 2); brushSizeSpinBox->setValue(5); brushSizeSpinBox->setExponentRatio(3.0); brushSizeSpinBox->setSuffix(i18n(" px")); brushSizeSpinBox->setExponentRatio(3.0); QObject::connect(brushSizeSpinBox, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetItemSize(qreal))); brushRotationSpinBox->setRange(0, 360, 0); brushRotationSpinBox->setValue(0); brushRotationSpinBox->setSuffix(QChar(Qt::Key_degree)); QObject::connect(brushRotationSpinBox, SIGNAL(valueChanged(qreal)), this, SLOT(slotSetItemRotation(qreal))); brushSpacingSelectionWidget->setSpacing(true, 1.0); connect(brushSpacingSelectionWidget, SIGNAL(sigSpacingChanged()), SLOT(slotSpacingChanged())); QObject::connect(useColorAsMaskCheckbox, SIGNAL(toggled(bool)), this, SLOT(slotSetItemUseColorAsMask(bool))); KisBrushResourceServer* rServer = KisBrushServer::instance()->brushServer(); QSharedPointer adapter(new KisBrushResourceServerAdapter(rServer)); m_itemChooser = new KoResourceItemChooser(adapter, this); m_itemChooser->setObjectName("brush_selector"); m_itemChooser->showTaggingBar(true); m_itemChooser->setColumnCount(10); m_itemChooser->setRowHeight(30); m_itemChooser->setItemDelegate(new KisBrushDelegate(this)); m_itemChooser->setCurrentItem(0, 0); m_itemChooser->setSynced(true); m_itemChooser->setMinimumWidth(100); m_itemChooser->setMinimumHeight(150); m_itemChooser->showButtons(false); // turn the import and delete buttons since we want control over them addPresetButton->setIcon(KisIconUtils::loadIcon("list-add")); deleteBrushTipButton->setIcon(KisIconUtils::loadIcon("trash-empty")); connect(addPresetButton, SIGNAL(clicked(bool)), this, SLOT(slotImportNewBrushResource())); connect(deleteBrushTipButton, SIGNAL(clicked(bool)), this, SLOT(slotDeleteBrushResource())); presetsLayout->addWidget(m_itemChooser); - connect(m_itemChooser, SIGNAL(resourceSelected(KoResource*)), this, SLOT(updateBrushTip(KoResource*))); + connect(m_itemChooser, SIGNAL(resourceSelected(KoResourceSP )), this, SLOT(updateBrushTip(KoResourceSP ))); stampButton->setIcon(KisIconUtils::loadIcon("list-add")); stampButton->setToolTip(i18n("Creates a brush tip from the current image selection." "\n If no selection is present the whole image will be used.")); clipboardButton->setIcon(KisIconUtils::loadIcon("list-add")); clipboardButton->setToolTip(i18n("Creates a brush tip from the image in the clipboard.")); connect(stampButton, SIGNAL(clicked()), this, SLOT(slotOpenStampBrush())); connect(clipboardButton, SIGNAL(clicked()), SLOT(slotOpenClipboardBrush())); QGridLayout *spacingLayout = new QGridLayout(); spacingLayout->setObjectName("spacing grid layout"); resetBrushButton->setToolTip(i18n("Reloads Spacing from file\nSets Scale to 1.0\nSets Rotation to 0.0")); connect(resetBrushButton, SIGNAL(clicked()), SLOT(slotResetBrush())); updateBrushTip(m_itemChooser->currentResource()); } KisPredefinedBrushChooser::~KisPredefinedBrushChooser() { } void KisPredefinedBrushChooser::setBrush(KisBrushSP brush) { /** * Warning: since the brushes are always cloned after loading from XML or * fetching from the server, we cannot just ask for that brush explicitly. * Instead, we should search for the brush with the same filename and/or name * and load it. Please take it into account that after selecting the brush * explicitly in the chooser, m_itemChooser->currentResource() might be * **not** the same as the value in m_brush. * * Ideally, if the resource is not found on the server, we should add it, but * it might lead to a set of weird consequences. So for now we just * select nothing. */ KisBrushResourceServer* server = KisBrushServer::instance()->brushServer(); - KoResource *resource = server->resourceByFilename(brush->shortFilename()).data(); + KoResourceSP resource = server->resourceByFilename(brush->shortFilename()); if (!resource) { - resource = server->resourceByName(brush->name()).data(); + resource = server->resourceByName(brush->name()); } if (!resource) { - resource = brush.data(); + resource = brush; } m_itemChooser->setCurrentResource(resource); - updateBrushTip(brush.data(), true); + updateBrushTip(brush, true); } void KisPredefinedBrushChooser::slotResetBrush() { /** * The slot also resets the brush on the server * * TODO: technically, after we refactored all the brushes to be forked, * we can just re-update the brush from the server without reloading. * But it needs testing. */ - KisBrush *brush = dynamic_cast(m_itemChooser->currentResource()); + KisBrushSP brush = m_itemChooser->currentResource().dynamicCast(); if (brush) { brush->load(); brush->setScale(1.0); brush->setAngle(0.0); updateBrushTip(brush); emit sigBrushChanged(); } } void KisPredefinedBrushChooser::slotSetItemSize(qreal sizeValue) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_brush); if (m_brush) { int brushWidth = m_brush->width(); m_brush->setScale(sizeValue / qreal(brushWidth)); emit sigBrushChanged(); } } void KisPredefinedBrushChooser::slotSetItemRotation(qreal rotationValue) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_brush); if (m_brush) { m_brush->setAngle(rotationValue / 180.0 * M_PI); emit sigBrushChanged(); } } void KisPredefinedBrushChooser::slotSpacingChanged() { KIS_SAFE_ASSERT_RECOVER_RETURN(m_brush); if (m_brush) { m_brush->setSpacing(brushSpacingSelectionWidget->spacing()); m_brush->setAutoSpacing(brushSpacingSelectionWidget->autoSpacingActive(), brushSpacingSelectionWidget->autoSpacingCoeff()); emit sigBrushChanged(); } } void KisPredefinedBrushChooser::slotSetItemUseColorAsMask(bool useColorAsMask) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_brush); KisGbrBrush *brush = dynamic_cast(m_brush.data()); if (brush) { brush->setUseColorAsMask(useColorAsMask); emit sigBrushChanged(); } } void KisPredefinedBrushChooser::slotOpenStampBrush() { if(!m_stampBrushWidget) { m_stampBrushWidget = new KisCustomBrushWidget(this, i18n("Stamp"), m_image); m_stampBrushWidget->setModal(false); - connect(m_stampBrushWidget, SIGNAL(sigNewPredefinedBrush(KoResource*)), - SLOT(slotNewPredefinedBrush(KoResource*))); + connect(m_stampBrushWidget, SIGNAL(sigNewPredefinedBrush(KoResourceSP )), + SLOT(slotNewPredefinedBrush(KoResourceSP ))); } QDialog::DialogCode result = (QDialog::DialogCode)m_stampBrushWidget->exec(); if(result) { updateBrushTip(m_itemChooser->currentResource()); } } void KisPredefinedBrushChooser::slotOpenClipboardBrush() { if(!m_clipboardBrushWidget) { m_clipboardBrushWidget = new KisClipboardBrushWidget(this, i18n("Clipboard"), m_image); m_clipboardBrushWidget->setModal(true); - connect(m_clipboardBrushWidget, SIGNAL(sigNewPredefinedBrush(KoResource*)), - SLOT(slotNewPredefinedBrush(KoResource*))); + connect(m_clipboardBrushWidget, SIGNAL(sigNewPredefinedBrush(KoResourceSP )), + SLOT(slotNewPredefinedBrush(KoResourceSP ))); } QDialog::DialogCode result = (QDialog::DialogCode)m_clipboardBrushWidget->exec(); if(result) { updateBrushTip(m_itemChooser->currentResource()); } } -void KisPredefinedBrushChooser::updateBrushTip(KoResource * resource, bool isChangingBrushPresets) +void KisPredefinedBrushChooser::updateBrushTip(KoResourceSP resource, bool isChangingBrushPresets) { QString animatedBrushTipSelectionMode; // incremental, random, etc { - KisBrush* brush = dynamic_cast(resource); + KisBrushSP brush = resource.dynamicCast(); m_brush = brush ? brush->clone() : 0; } if (m_brush) { brushTipNameLabel->setText(i18n(m_brush->name().toUtf8().data())); QString brushTypeString = ""; if (m_brush->brushType() == INVALID) { brushTypeString = i18n("Invalid"); } else if (m_brush->brushType() == MASK) { brushTypeString = i18n("Mask"); } else if (m_brush->brushType() == IMAGE) { brushTypeString = i18n("GBR"); } else if (m_brush->brushType() == PIPE_MASK ) { brushTypeString = i18n("Animated Mask"); // GIH brush // cast to GIH brush and grab parasite name //m_brush - KisImagePipeBrush* pipeBrush = dynamic_cast(resource); + KisImagePipeBrushSP pipeBrush = resource.dynamicCast(); animatedBrushTipSelectionMode = pipeBrush->parasiteSelection(); } else if (m_brush->brushType() == PIPE_IMAGE ) { brushTypeString = i18n("Animated Image"); } QString brushDetailsText = QString("%1 (%2 x %3) %4") .arg(brushTypeString) .arg(m_brush->width()) .arg(m_brush->height()) .arg(animatedBrushTipSelectionMode); brushDetailsLabel->setText(brushDetailsText); // keep the current preset's tip settings if we are preserving it // this will set the brush's model data to keep what it currently has for size, spacing, etc. if (preserveBrushPresetSettings->isChecked() && !isChangingBrushPresets) { m_brush->setAutoSpacing(brushSpacingSelectionWidget->autoSpacingActive(), brushSpacingSelectionWidget->autoSpacingCoeff()); m_brush->setAngle(brushRotationSpinBox->value() * M_PI / 180); m_brush->setSpacing(brushSpacingSelectionWidget->spacing()); m_brush->setUserEffectiveSize(brushSizeSpinBox->value()); } brushSpacingSelectionWidget->setSpacing(m_brush->autoSpacingActive(), m_brush->autoSpacingActive() ? m_brush->autoSpacingCoeff() : m_brush->spacing()); brushRotationSpinBox->setValue(m_brush->angle() * 180 / M_PI); brushSizeSpinBox->setValue(m_brush->width() * m_brush->scale()); // useColorAsMask support is only in gimp brush so far KisGbrBrush *gimpBrush = dynamic_cast(m_brush.data()); if (gimpBrush) { useColorAsMaskCheckbox->setChecked(gimpBrush->useColorAsMask()); } useColorAsMaskCheckbox->setEnabled(m_brush->hasColor() && gimpBrush); emit sigBrushChanged(); } } -void KisPredefinedBrushChooser::slotNewPredefinedBrush(KoResource *resource) +void KisPredefinedBrushChooser::slotNewPredefinedBrush(KoResourceSP resource) { m_itemChooser->setCurrentResource(resource); updateBrushTip(resource); } void KisPredefinedBrushChooser::setBrushSize(qreal xPixels, qreal yPixels) { Q_UNUSED(yPixels); qreal oldWidth = m_brush->width() * m_brush->scale(); qreal newWidth = oldWidth + xPixels; newWidth = qMax(newWidth, qreal(0.1)); brushSizeSpinBox->setValue(newWidth); } void KisPredefinedBrushChooser::setImage(KisImageWSP image) { m_image = image; } void KisPredefinedBrushChooser::slotImportNewBrushResource() { m_itemChooser->slotButtonClicked(KoResourceItemChooser::Button_Import); } void KisPredefinedBrushChooser::slotDeleteBrushResource() { m_itemChooser->slotButtonClicked(KoResourceItemChooser::Button_Remove); } #include "moc_kis_brush_chooser.cpp" diff --git a/plugins/paintops/libpaintop/kis_brush_chooser.h b/plugins/paintops/libpaintop/kis_brush_chooser.h index a61958e68b..114ec1dfc8 100644 --- a/plugins/paintops/libpaintop/kis_brush_chooser.h +++ b/plugins/paintops/libpaintop/kis_brush_chooser.h @@ -1,86 +1,86 @@ /* * Copyright (c) 2004 Adrian Page * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_PREDEFINED_BRUSH_CHOOSER_H_ #define KIS_PREDEFINED_BRUSH_CHOOSER_H_ #include #include #include #include "kritapaintop_export.h" #include "ui_wdgpredefinedbrushchooser.h" class KisDoubleSliderSpinBox; class QLabel; class QCheckBox; class KisDoubleSliderSpinBox; class KisSpacingSelectionWidget; class KisCustomBrushWidget; class KisClipboardBrushWidget; class KoResourceItemChooser; class KoResource; class PAINTOP_EXPORT KisPredefinedBrushChooser : public QWidget, Ui::WdgPredefinedBrushChooser { Q_OBJECT public: KisPredefinedBrushChooser(QWidget *parent = 0, const char *name = 0); ~KisPredefinedBrushChooser() override; KisBrushSP brush() { return m_brush; }; void setBrush(KisBrushSP brush); void setBrushSize(qreal xPixels, qreal yPixels); void setImage(KisImageWSP image); private Q_SLOTS: void slotResetBrush(); void slotSetItemSize(qreal); void slotSetItemRotation(qreal); void slotSpacingChanged(); void slotSetItemUseColorAsMask(bool); void slotOpenStampBrush(); void slotOpenClipboardBrush(); void slotImportNewBrushResource(); void slotDeleteBrushResource(); - void slotNewPredefinedBrush(KoResource *); - void updateBrushTip(KoResource *, bool isChangingBrushPresets = false); + void slotNewPredefinedBrush(KoResourceSP ); + void updateBrushTip(KoResourceSP , bool isChangingBrushPresets = false); Q_SIGNALS: void sigBrushChanged(); private: KisBrushSP m_brush; KoResourceItemChooser* m_itemChooser; KisImageWSP m_image; KisCustomBrushWidget* m_stampBrushWidget; KisClipboardBrushWidget* m_clipboardBrushWidget; }; #endif // KIS_PREDEFINED_BRUSH_CHOOSER_H_ diff --git a/plugins/paintops/libpaintop/kis_clipboard_brush_widget.cpp b/plugins/paintops/libpaintop/kis_clipboard_brush_widget.cpp index 0920a5f7b8..39460cc591 100644 --- a/plugins/paintops/libpaintop/kis_clipboard_brush_widget.cpp +++ b/plugins/paintops/libpaintop/kis_clipboard_brush_widget.cpp @@ -1,160 +1,160 @@ /* * Copyright (c) 2005 Bart Coppens * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2013 Somsubhra Bairi * * 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_clipboard_brush_widget.h" #include #include #include #include #include #include #include #include "kis_image.h" #include "kis_clipboard.h" #include "kis_paint_device.h" #include "kis_gbr_brush.h" #include "kis_brush_server.h" KisClipboardBrushWidget::KisClipboardBrushWidget(QWidget *parent, const QString &caption, KisImageWSP image) : KisWdgClipboardBrush(parent), m_image(image) { setWindowTitle(caption); preview->setScaledContents(true); preview->setFixedSize(preview->size()); preview->setStyleSheet("border: 2px solid #222; border-radius: 4px; padding: 5px; font: normal 10px;"); KisBrushResourceServer* rServer = KisBrushServer::instance()->brushServer(); m_rServerAdapter = QSharedPointer(new KisBrushResourceServerAdapter(rServer)); m_brush = 0; m_clipboard = KisClipboard::instance(); connect(m_clipboard, SIGNAL(clipChanged()), this, SLOT(slotCreateBrush())); connect(colorAsmask, SIGNAL(toggled(bool)), this, SLOT(slotUpdateUseColorAsMask(bool))); connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotAddPredefined())); spacingWidget->setSpacing(true, 1.0); connect(spacingWidget, SIGNAL(sigSpacingChanged()), SLOT(slotSpacingChanged())); } KisClipboardBrushWidget::~KisClipboardBrushWidget() { } void KisClipboardBrushWidget::slotCreateBrush() { // do nothing if it's hidden otherwise it can break the active brush is something is copied if (m_clipboard->hasClip() && !isHidden()) { pd = m_clipboard->clip(QRect(0, 0, 0, 0), false); //Weird! Don't know how this works! if (pd) { QRect rc = pd->exactBounds(); - m_brush = new KisGbrBrush(pd, rc.x(), rc.y(), rc.width(), rc.height()); + m_brush = KisBrushSP(new KisGbrBrush(pd, rc.x(), rc.y(), rc.width(), rc.height())); m_brush->setSpacing(spacingWidget->spacing()); m_brush->setAutoSpacing(spacingWidget->autoSpacingActive(), spacingWidget->autoSpacingCoeff()); m_brush->setFilename(TEMPORARY_CLIPBOARD_BRUSH_FILENAME); m_brush->setName(TEMPORARY_CLIPBOARD_BRUSH_NAME); m_brush->setValid(true); preview->setPixmap(QPixmap::fromImage(m_brush->image())); } } else { preview->setText(i18n("Nothing copied\n to Clipboard")); } - if(m_brush == 0) { + if (!m_brush) { buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); } else { buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); colorAsmask->setChecked(true); // initializing this has to happen here since we need a valid brush for it to work } } void KisClipboardBrushWidget::slotSpacingChanged() { if (m_brush) { m_brush->setSpacing(spacingWidget->spacing()); m_brush->setAutoSpacing(spacingWidget->autoSpacingActive(), spacingWidget->autoSpacingCoeff()); } } void KisClipboardBrushWidget::showEvent(QShowEvent *) { slotCreateBrush(); } void KisClipboardBrushWidget::slotUpdateUseColorAsMask(bool useColorAsMask) { if (m_brush) { static_cast(m_brush.data())->setUseColorAsMask(useColorAsMask); preview->setPixmap(QPixmap::fromImage(m_brush->brushTipImage())); } } void KisClipboardBrushWidget::slotAddPredefined() { if(!m_brush) return; QString dir = KoResourcePaths::saveLocation("data", "brushes"); QString extension = ".gbr"; QString name = nameEdit->text(); QString tempFileName; QFileInfo fileInfo; fileInfo.setFile(dir + name + extension); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(dir + name + QString("%1").arg(i) + extension); i++; } tempFileName = fileInfo.filePath(); if (m_rServerAdapter) { - KisGbrBrush *resource = dynamic_cast(m_brush->clone()); + KisGbrBrushSP resource = m_brush->clone().dynamicCast(); resource->setFilename(tempFileName); if (nameEdit->text().isEmpty()) { resource->setName(QDateTime::currentDateTime().toString("yyyy-MM-ddThh:mm")); } else { resource->setName(name); } if (colorAsmask->isChecked()) { resource->makeMaskImage(); } m_rServerAdapter->addResource(resource); emit sigNewPredefinedBrush(resource); } close(); } #include "moc_kis_clipboard_brush_widget.cpp" diff --git a/plugins/paintops/libpaintop/kis_clipboard_brush_widget.h b/plugins/paintops/libpaintop/kis_clipboard_brush_widget.h index 7d2e13997b..321210edd0 100644 --- a/plugins/paintops/libpaintop/kis_clipboard_brush_widget.h +++ b/plugins/paintops/libpaintop/kis_clipboard_brush_widget.h @@ -1,78 +1,78 @@ /* * Copyright (c) 2005 Bart Coppens * Copyright (c) 2013 Somsubhra Bairi * * 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_CLIPBOARD_BRUSH_WIDGET_H #define KIS_CLIPBOARD_BRUSH_WIDGET_H //Qt includes #include #include //Calligra includes #include //Krita includes #include #include #include "ui_wdgclipboardbrush.h" const QString TEMPORARY_CLIPBOARD_BRUSH_FILENAME = "/tmp/temporaryClipboardBrush.gbr"; const QString TEMPORARY_CLIPBOARD_BRUSH_NAME = "Temporary clipboard brush"; const double DEFAULT_CLIPBOARD_BRUSH_SPACING = 0.25; class KisClipboard; class KoResource; class KisWdgClipboardBrush : public QDialog, public Ui::KisWdgClipboardBrush { Q_OBJECT public: KisWdgClipboardBrush(QWidget* parent) : QDialog(parent) { setupUi(this); } }; class KisClipboardBrushWidget : public KisWdgClipboardBrush { Q_OBJECT public: KisClipboardBrushWidget(QWidget* parent, const QString& caption, KisImageWSP image); virtual ~KisClipboardBrushWidget(); private Q_SLOTS: void slotCreateBrush(); void slotSpacingChanged(); void slotUpdateUseColorAsMask(bool useColorAsMask); void slotAddPredefined(); protected: void showEvent(QShowEvent *); Q_SIGNALS: - void sigNewPredefinedBrush(KoResource *); + void sigNewPredefinedBrush(KoResourceSP ); private: KisClipboard* m_clipboard; KisPaintDeviceSP pd; KisImageWSP m_image; KisBrushSP m_brush; QSharedPointer m_rServerAdapter; }; #endif // KIS_CLIPBOARD_BRUSH_WIDGET_H diff --git a/plugins/paintops/libpaintop/kis_color_source.cpp b/plugins/paintops/libpaintop/kis_color_source.cpp index ae2bca7f10..56f49909f9 100644 --- a/plugins/paintops/libpaintop/kis_color_source.cpp +++ b/plugins/paintops/libpaintop/kis_color_source.cpp @@ -1,296 +1,296 @@ /* * Copyright (c) 2006-2007, 2009 Cyrille Berger * * 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; version 2.1 of the License. * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_color_source.h" #include #include #include #include #include #include #include #include "kis_iterator_ng.h" #include "kis_selection.h" #include #include #include KisColorSource::~KisColorSource() { } const KoColor black; const KoColor& KisColorSource::uniformColor() const { qFatal("Not an uniform color."); return black; } KisUniformColorSource::KisUniformColorSource() { } KisUniformColorSource::~KisUniformColorSource() { } void KisUniformColorSource::rotate(double) {} void KisUniformColorSource::resize(double , double) { // Do nothing as plain color does not have size } void KisUniformColorSource::colorize(KisPaintDeviceSP dev, const QRect& size, const QPoint&) const { Q_UNUSED(size); KoColor c(dev->colorSpace()); c.fromKoColor(m_color); dev->dataManager()->setDefaultPixel(c.data()); dev->clear(); } const KoColor& KisUniformColorSource::uniformColor() const { return m_color; } void KisUniformColorSource::applyColorTransformation(const KoColorTransformation* transfo) { transfo->transform(m_color.data(), m_color.data(), 1); } const KoColorSpace* KisUniformColorSource::colorSpace() const { return m_color.colorSpace(); } bool KisUniformColorSource::isUniformColor() const { return true; } //-------------------------------------------------// //---------------- KisPlainColorSource ---------------// //-------------------------------------------------// KisPlainColorSource::KisPlainColorSource(const KoColor& backGroundColor, const KoColor& foreGroundColor) : m_backGroundColor(backGroundColor) , m_cachedBackGroundColor(backGroundColor) , m_foreGroundColor(foreGroundColor) { } KisPlainColorSource::~KisPlainColorSource() { } void KisPlainColorSource::selectColor(double mix, const KisPaintInformation &pi) { Q_UNUSED(pi); if (m_color.colorSpace() != m_foreGroundColor.colorSpace()) { m_color = KoColor(m_foreGroundColor.colorSpace()); m_cachedBackGroundColor = KoColor(m_foreGroundColor.colorSpace()); m_cachedBackGroundColor.fromKoColor(m_backGroundColor); } const quint8 *colors[2]; colors[0] = m_cachedBackGroundColor.data(); colors[1] = m_foreGroundColor.data(); // equally distribute mix factor over [0..255] // mix * 256 ensures that, with exception of mix==1.0, which gets special handling const int weight = (mix == 1.0) ? 255 : (int)(mix * 256); const qint16 weights[2] = { (qint16)(255 - weight), (qint16)weight }; m_color.colorSpace()->mixColorsOp()->mixColors(colors, weights, 2, m_color.data()); } //-------------------------------------------------// //--------------- KisGradientColorSource -------------// //-------------------------------------------------// -KisGradientColorSource::KisGradientColorSource(const KoAbstractGradient* gradient, const KoColorSpace* workingCS) +KisGradientColorSource::KisGradientColorSource(const KoAbstractGradientSP gradient, const KoColorSpace* workingCS) : m_gradient(gradient) { m_color = KoColor(workingCS); Q_ASSERT(gradient); } KisGradientColorSource::~KisGradientColorSource() { } void KisGradientColorSource::selectColor(double mix, const KisPaintInformation &pi) { Q_UNUSED(pi); if (m_gradient) { m_gradient->colorAt(m_color, mix); } } //-------------------------------------------------// //--------------- KisGradientColorSource -------------// //-------------------------------------------------// KisUniformRandomColorSource::KisUniformRandomColorSource() { } KisUniformRandomColorSource::~KisUniformRandomColorSource() { } void KisUniformRandomColorSource::selectColor(double mix, const KisPaintInformation &pi) { Q_UNUSED(pi); Q_UNUSED(mix); KisRandomSourceSP source = pi.randomSource(); m_color.fromQColor(QColor((int)source->generate(0, 255), (int)source->generate(0, 255), (int)source->generate(0, 255))); } //------------------------------------------------------// //--------------- KisTotalRandomColorSource ---------------// //------------------------------------------------------// KisTotalRandomColorSource::KisTotalRandomColorSource() : m_colorSpace(KoColorSpaceRegistry::instance()->rgb8()) { } KisTotalRandomColorSource::~KisTotalRandomColorSource() { } void KisTotalRandomColorSource::selectColor(double mix, const KisPaintInformation &pi) { Q_UNUSED(mix); Q_UNUSED(pi); } void KisTotalRandomColorSource::applyColorTransformation(const KoColorTransformation*) {} const KoColorSpace* KisTotalRandomColorSource::colorSpace() const { return m_colorSpace; } void KisTotalRandomColorSource::colorize(KisPaintDeviceSP dev, const QRect& rect, const QPoint&) const { KoColor kc(dev->colorSpace()); QColor qc; std::random_device rand_dev; std::default_random_engine rand_engine{rand_dev()}; std::uniform_int_distribution<> rand_distr(0, 255); int pixelSize = dev->colorSpace()->pixelSize(); KisHLineIteratorSP it = dev->createHLineIteratorNG(rect.x(), rect.y(), rect.width()); for (int y = 0; y < rect.height(); y++) { do { qc.setRgb(rand_distr(rand_engine), rand_distr(rand_engine), rand_distr(rand_engine)); kc.fromQColor(qc); memcpy(it->rawData(), kc.data(), pixelSize); } while (it->nextPixel()); it->nextRow(); } } bool KisTotalRandomColorSource::isUniformColor() const { return false; } void KisTotalRandomColorSource::rotate(double) {} void KisTotalRandomColorSource::resize(double , double) {} KoPatternColorSource::KoPatternColorSource(KisPaintDeviceSP _pattern, int _width, int _height, bool _locked) : m_device(_pattern) , m_bounds(QRect(0, 0, _width, _height)) , m_locked(_locked) { } KoPatternColorSource::~KoPatternColorSource() { } void KoPatternColorSource::selectColor(double mix, const KisPaintInformation &pi) { Q_UNUSED(mix); Q_UNUSED(pi); } void KoPatternColorSource::applyColorTransformation(const KoColorTransformation* transfo) { Q_UNUSED(transfo); } const KoColorSpace* KoPatternColorSource::colorSpace() const { return m_device->colorSpace(); } void KoPatternColorSource::colorize(KisPaintDeviceSP device, const QRect& rect, const QPoint& offset) const { KisFillPainter painter(device); if (m_locked) { painter.fillRect(rect.x(), rect.y(), rect.width(), rect.height(), m_device, m_bounds); } else { int x = offset.x() % m_bounds.width(); int y = offset.y() % m_bounds.height(); // Change the position, because the pattern is always applied starting // from (0,0) in the paint device reference device->setX(x); device->setY(y); painter.fillRect(rect.x() + x, rect.y() + y, rect.width(), rect.height(), m_device, m_bounds); device->setX(0); device->setY(0); } } void KoPatternColorSource::rotate(double r) { Q_UNUSED(r); } void KoPatternColorSource::resize(double xs, double ys) { Q_UNUSED(xs); Q_UNUSED(ys); } bool KoPatternColorSource::isUniformColor() const { return false; } diff --git a/plugins/paintops/libpaintop/kis_color_source.h b/plugins/paintops/libpaintop/kis_color_source.h index eb8386f9c5..4944c30600 100644 --- a/plugins/paintops/libpaintop/kis_color_source.h +++ b/plugins/paintops/libpaintop/kis_color_source.h @@ -1,151 +1,151 @@ /* * Copyright (c) 2006-2007, 2009 Cyrille Berger * * 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; version 2.1 of the License. * * 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 program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KIS_DYNAMIC_COLORING_H_ #define _KIS_DYNAMIC_COLORING_H_ #include "kis_paintop_option.h" #include #include +#include #include #include -class KoAbstractGradient; class KoColorTransformation; class KisPaintInformation; /** * A color source allow to abstract how a brush is colorized, * and to apply transformation. * * The first function to call is @ref selectColor , then any of the transformation. */ class PAINTOP_EXPORT KisColorSource { public: virtual ~KisColorSource(); public: /** * This is function is called to initialize the color that will be used for the dab. * @param mix is a parameter between 0.0 and 1.0 */ virtual void selectColor(double mix, const KisPaintInformation &pi) = 0; /** * Apply a color transformation on the selected color */ virtual void applyColorTransformation(const KoColorTransformation* transfo) = 0; virtual const KoColorSpace* colorSpace() const = 0; /** * Apply the color on a paint device */ virtual void colorize(KisPaintDeviceSP, const QRect& rect, const QPoint& _offset) const = 0; /** * @return true if the color is an uniform color */ virtual bool isUniformColor() const = 0; /** * @return the color if the color is uniformed */ virtual const KoColor& uniformColor() const; }; class PAINTOP_EXPORT KisUniformColorSource : public KisColorSource { public: KisUniformColorSource(); ~KisUniformColorSource() override; virtual void rotate(double); virtual void resize(double , double); void applyColorTransformation(const KoColorTransformation* transfo) override; const KoColorSpace* colorSpace() const override; void colorize(KisPaintDeviceSP, const QRect& rect, const QPoint& offset) const override; bool isUniformColor() const override; const KoColor& uniformColor() const override; protected: KoColor m_color; }; class PAINTOP_EXPORT KisPlainColorSource : public KisUniformColorSource { public: KisPlainColorSource(const KoColor& backGroundColor, const KoColor& foreGroundColor); ~KisPlainColorSource() override; void selectColor(double mix, const KisPaintInformation &pi) override; private: KoColor m_backGroundColor; KoColor m_cachedBackGroundColor; KoColor m_foreGroundColor; }; class PAINTOP_EXPORT KisGradientColorSource : public KisUniformColorSource { public: - KisGradientColorSource(const KoAbstractGradient* gradient, const KoColorSpace* workingCS); + KisGradientColorSource(const KoAbstractGradientSP gradient, const KoColorSpace* workingCS); ~KisGradientColorSource() override; void selectColor(double mix, const KisPaintInformation &pi) override; private: - const KoAbstractGradient* m_gradient; + const KoAbstractGradientSP m_gradient; }; class PAINTOP_EXPORT KisUniformRandomColorSource : public KisUniformColorSource { public: KisUniformRandomColorSource(); ~KisUniformRandomColorSource() override; void selectColor(double mix, const KisPaintInformation &pi) override; }; class PAINTOP_EXPORT KisTotalRandomColorSource : public KisColorSource { public: KisTotalRandomColorSource(); ~KisTotalRandomColorSource() override; public: void selectColor(double mix, const KisPaintInformation &pi) override; void applyColorTransformation(const KoColorTransformation* transfo) override; const KoColorSpace* colorSpace() const override; void colorize(KisPaintDeviceSP, const QRect& rect, const QPoint& offset) const override; virtual void rotate(double r); virtual void resize(double xs, double ys); bool isUniformColor() const override; private: const KoColorSpace* m_colorSpace; }; class PAINTOP_EXPORT KoPatternColorSource : public KisColorSource { public: KoPatternColorSource(KisPaintDeviceSP _pattern, int _width, int _height, bool _locked); ~KoPatternColorSource() override; public: void selectColor(double mix, const KisPaintInformation &pi) override; void applyColorTransformation(const KoColorTransformation* transfo) override; const KoColorSpace* colorSpace() const override; void colorize(KisPaintDeviceSP, const QRect& rect, const QPoint& _offset) const override; virtual void rotate(double r); virtual void resize(double xs, double ys); bool isUniformColor() const override; private: const KisPaintDeviceSP m_device; QRect m_bounds; bool m_locked; }; #endif diff --git a/plugins/paintops/libpaintop/kis_custom_brush_widget.cpp b/plugins/paintops/libpaintop/kis_custom_brush_widget.cpp index 217bcb9c52..e7c1aabf14 100644 --- a/plugins/paintops/libpaintop/kis_custom_brush_widget.cpp +++ b/plugins/paintops/libpaintop/kis_custom_brush_widget.cpp @@ -1,260 +1,260 @@ /* * Copyright (c) 2005 Bart Coppens * Copyright (c) 2010 Lukáš Tvrdý * * 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_custom_brush_widget.h" #include #include #include #include #include #include #include #include #include #include #include "kis_image.h" #include "kis_layer.h" #include "kis_paint_device.h" #include "kis_gbr_brush.h" #include "kis_imagepipe_brush.h" #include #include "kis_brush_server.h" #include "kis_paint_layer.h" #include "kis_group_layer.h" #include #include #include "kis_iterator_ng.h" KisCustomBrushWidget::KisCustomBrushWidget(QWidget *parent, const QString& caption, KisImageWSP image) : KisWdgCustomBrush(parent) , m_image(image) { setWindowTitle(caption); preview->setScaledContents(false); preview->setFixedSize(preview->size()); preview->setStyleSheet("border: 2px solid #222; border-radius: 4px; padding: 5px; font: normal 10px;"); KisBrushResourceServer* rServer = KisBrushServer::instance()->brushServer(); m_rServerAdapter = QSharedPointer(new KisBrushResourceServerAdapter(rServer)); m_brush = 0; connect(this, SIGNAL(accepted()), SLOT(slotAddPredefined())); connect(brushStyle, SIGNAL(activated(int)), this, SLOT(slotUpdateCurrentBrush(int))); connect(colorAsMask, SIGNAL(toggled(bool)), this, SLOT(slotUpdateUseColorAsMask(bool))); colorAsMask->setChecked(true); // use color as mask by default. This is by far the most common way to make tip. spacingWidget->setSpacing(true, 1.0); connect(spacingWidget, SIGNAL(sigSpacingChanged()), SLOT(slotSpacingChanged())); } KisCustomBrushWidget::~KisCustomBrushWidget() { } KisBrushSP KisCustomBrushWidget::brush() { return m_brush; } void KisCustomBrushWidget::showEvent(QShowEvent *) { slotUpdateCurrentBrush(0); } void KisCustomBrushWidget::updatePreviewImage() { QImage brushImage = m_brush ? m_brush->brushTipImage() : QImage(); if (!brushImage.isNull()) { brushImage = brushImage.scaled(preview->size(), Qt::KeepAspectRatio); } preview->setPixmap(QPixmap::fromImage(brushImage)); } void KisCustomBrushWidget::slotUpdateCurrentBrush(int) { if (brushStyle->currentIndex() == 0) { comboBox2->setEnabled(false); } else { comboBox2->setEnabled(true); } if (m_image) { createBrush(); updatePreviewImage(); } } void KisCustomBrushWidget::slotSpacingChanged() { if (m_brush) { m_brush->setSpacing(spacingWidget->spacing()); m_brush->setAutoSpacing(spacingWidget->autoSpacingActive(), spacingWidget->autoSpacingCoeff()); } } void KisCustomBrushWidget::slotUpdateUseColorAsMask(bool useColorAsMask) { if (m_brush) { static_cast(m_brush.data())->setUseColorAsMask(useColorAsMask); updatePreviewImage(); } } void KisCustomBrushWidget::slotAddPredefined() { QString dir = KoResourcePaths::saveLocation("data", "brushes"); QString extension; if (brushStyle->currentIndex() == 0) { extension = ".gbr"; } else { extension = ".gih"; } QString name = nameLineEdit->text(); QString tempFileName; { QFileInfo fileInfo; fileInfo.setFile(dir + name + extension); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(dir + name + QString("%1").arg(i) + extension); i++; } tempFileName = fileInfo.filePath(); } // Add it to the brush server, so that it automatically gets to the mediators, and // so to the other brush choosers can pick it up, if they want to if (m_rServerAdapter && m_brush) { qDebug() << "m_brush" << m_brush; - KisGbrBrush *resource = dynamic_cast(m_brush->clone()); + KisGbrBrushSP resource = m_brush->clone().dynamicCast(); resource->setFilename(tempFileName); if (nameLineEdit->text().isEmpty()) { resource->setName(QDateTime::currentDateTime().toString("yyyy-MM-ddThh:mm")); } else { resource->setName(name); } if (colorAsMask->isChecked()) { resource->makeMaskImage(); } m_rServerAdapter->addResource(resource); emit sigNewPredefinedBrush(resource); } close(); } void KisCustomBrushWidget::createBrush() { if (!m_image) return; if (brushStyle->currentIndex() == 0) { KisSelectionSP selection = m_image->globalSelection(); // create copy of the data m_image->lock(); KisPaintDeviceSP dev = new KisPaintDevice(*m_image->projection()); m_image->unlock(); if (!selection) { - m_brush = new KisGbrBrush(dev, 0, 0, m_image->width(), m_image->height()); + m_brush = KisBrushSP(new KisGbrBrush(dev, 0, 0, m_image->width(), m_image->height())); } else { // apply selection mask QRect r = selection->selectedExactRect(); dev->crop(r); KisHLineIteratorSP pixelIt = dev->createHLineIteratorNG(r.x(), r.top(), r.width()); KisHLineConstIteratorSP maskIt = selection->projection()->createHLineIteratorNG(r.x(), r.top(), r.width()); for (qint32 y = r.top(); y <= r.bottom(); ++y) { do { dev->colorSpace()->applyAlphaU8Mask(pixelIt->rawData(), maskIt->oldRawData(), 1); } while (pixelIt->nextPixel() && maskIt->nextPixel()); pixelIt->nextRow(); maskIt->nextRow(); } QRect rc = dev->exactBounds(); - m_brush = new KisGbrBrush(dev, rc.x(), rc.y(), rc.width(), rc.height()); + m_brush = KisBrushSP(new KisGbrBrush(dev, rc.x(), rc.y(), rc.width(), rc.height())); } } else { // For each layer in the current image, create a new image, and add it to the list QVector< QVector > devices; devices.push_back(QVector()); int w = m_image->width(); int h = m_image->height(); m_image->lock(); // We only loop over the rootLayer. Since we actually should have a layer selection // list, no need to elaborate on that here and now KoProperties properties; properties.setProperty("visible", true); QList layers = m_image->root()->childNodes(QStringList("KisLayer"), properties); KisNodeSP node; Q_FOREACH (KisNodeSP node, layers) { devices[0].push_back(node->projection().data()); } QVector modes; switch (comboBox2->currentIndex()) { case 0: modes.push_back(KisParasite::Constant); break; case 1: modes.push_back(KisParasite::Random); break; case 2: modes.push_back(KisParasite::Incremental); break; case 3: modes.push_back(KisParasite::Pressure); break; case 4: modes.push_back(KisParasite::Angular); break; default: modes.push_back(KisParasite::Incremental); } - m_brush = new KisImagePipeBrush(m_image->objectName(), w, h, devices, modes); + m_brush = KisBrushSP(new KisImagePipeBrush(m_image->objectName(), w, h, devices, modes)); m_image->unlock(); } static_cast(m_brush.data())->setUseColorAsMask(colorAsMask->isChecked()); m_brush->setSpacing(spacingWidget->spacing()); m_brush->setAutoSpacing(spacingWidget->autoSpacingActive(), spacingWidget->autoSpacingCoeff()); m_brush->setFilename(TEMPORARY_FILENAME); m_brush->setName(TEMPORARY_BRUSH_NAME); m_brush->setValid(true); } diff --git a/plugins/paintops/libpaintop/kis_custom_brush_widget.h b/plugins/paintops/libpaintop/kis_custom_brush_widget.h index b4deb71bc8..e9211f1788 100644 --- a/plugins/paintops/libpaintop/kis_custom_brush_widget.h +++ b/plugins/paintops/libpaintop/kis_custom_brush_widget.h @@ -1,79 +1,79 @@ /* * Copyright (c) 2005 Bart Coppens * * 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_CUSTOM_BRUSH_H_ #define KIS_CUSTOM_BRUSH_H_ #include #include #include #include "ui_wdgcustombrush.h" #include #include const QString TEMPORARY_FILENAME = "/tmp/temporaryKritaBrush.gbr"; const QString TEMPORARY_BRUSH_NAME = "Temporary custom brush"; const double DEFAULT_SPACING = 0.25; class KoResource; class KisWdgCustomBrush : public QDialog, public Ui::KisWdgCustomBrush { Q_OBJECT public: KisWdgCustomBrush(QWidget *parent) : QDialog(parent) { setupUi(this); } }; class KisCustomBrushWidget : public KisWdgCustomBrush { Q_OBJECT public: KisCustomBrushWidget(QWidget *parent, const QString& caption, KisImageWSP image); virtual ~KisCustomBrushWidget(); KisBrushSP brush(); protected: virtual void showEvent(QShowEvent *); private Q_SLOTS: void slotAddPredefined(); void slotUpdateCurrentBrush(int i = 0); // To connect with activated(int) void slotSpacingChanged(); void slotUpdateUseColorAsMask(bool useColorAsMask); Q_SIGNALS: - void sigNewPredefinedBrush(KoResource *); + void sigNewPredefinedBrush(KoResourceSP ); private: void createBrush(); void updatePreviewImage(); KisImageWSP m_image; KisBrushSP m_brush; QSharedPointer m_rServerAdapter; }; #endif // KIS_CUSTOM_BRUSH_H_ diff --git a/plugins/paintops/libpaintop/kis_embedded_pattern_manager.cpp b/plugins/paintops/libpaintop/kis_embedded_pattern_manager.cpp index 7213d063f2..18983def59 100644 --- a/plugins/paintops/libpaintop/kis_embedded_pattern_manager.cpp +++ b/plugins/paintops/libpaintop/kis_embedded_pattern_manager.cpp @@ -1,104 +1,104 @@ /* * Copyright (c) 2013 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_embedded_pattern_manager.h" #include #include #include #include #include struct KisEmbeddedPatternManager::Private { - static KoPattern* tryLoadEmbeddedPattern(const KisPropertiesConfigurationSP setting) { - KoPattern *pattern = 0; + static KoPatternSP tryLoadEmbeddedPattern(const KisPropertiesConfigurationSP setting) { + KoPatternSP pattern; QByteArray ba = QByteArray::fromBase64(setting->getString("Texture/Pattern/Pattern").toLatin1()); QImage img; img.loadFromData(ba, "PNG"); QString name = setting->getString("Texture/Pattern/Name"); QString filename = setting->getString("Texture/Pattern/PatternFileName"); if (name.isEmpty() || name != QFileInfo(name).fileName()) { QFileInfo info(filename); name = info.baseName(); } if (!img.isNull()) { - pattern = new KoPattern(img, name, KoResourceServerProvider::instance()->patternServer()->saveLocation()); + pattern = KoPatternSP(new KoPattern(img, name, KoResourceServerProvider::instance()->patternServer()->saveLocation())); } return pattern; } }; -void KisEmbeddedPatternManager::saveEmbeddedPattern(KisPropertiesConfigurationSP setting, const KoPattern *pattern) +void KisEmbeddedPatternManager::saveEmbeddedPattern(KisPropertiesConfigurationSP setting, const KoPatternSP pattern) { QByteArray patternMD5 = pattern->md5(); /** * The process of saving a pattern may be quite expensive, so * we won't rewrite the pattern if has the same md5-sum and at * least some data is present */ QByteArray existingMD5 = QByteArray::fromBase64(setting->getString("Texture/Pattern/PatternMD5").toLatin1()); QString existingPatternBase64 = setting->getString("Texture/Pattern/PatternMD5").toLatin1(); if (patternMD5 == existingMD5 && !existingPatternBase64.isEmpty()) { return; } setting->setProperty("Texture/Pattern/PatternMD5", patternMD5.toBase64()); setting->setProperty("Texture/Pattern/PatternFileName", pattern->filename()); setting->setProperty("Texture/Pattern/Name", pattern->name()); QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); pattern->pattern().save(&buffer, "PNG"); setting->setProperty("Texture/Pattern/Pattern", ba.toBase64()); } -KoPattern* KisEmbeddedPatternManager::loadEmbeddedPattern(const KisPropertiesConfigurationSP setting) +KoPatternSP KisEmbeddedPatternManager::loadEmbeddedPattern(const KisPropertiesConfigurationSP setting) { - KoPattern *pattern = 0; + KoPatternSP pattern; KoResourceServer *server = KoResourceServerProvider::instance()->patternServer(); QByteArray md5 = QByteArray::fromBase64(setting->getString("Texture/Pattern/PatternMD5").toLatin1()); pattern = server->resourceByMD5(md5); if (pattern) return pattern; QString name = setting->getString("Texture/Pattern/Name"); pattern = server->resourceByName(name); if (pattern) return pattern; QString fileName = setting->getString("Texture/Pattern/PatternFileName"); pattern = server->resourceByFilename(fileName); if (pattern) return pattern; pattern = Private::tryLoadEmbeddedPattern(setting); if (pattern) { KoResourceServerProvider::instance()->patternServer()->addResource(pattern, false); } return pattern; } diff --git a/plugins/paintops/libpaintop/kis_embedded_pattern_manager.h b/plugins/paintops/libpaintop/kis_embedded_pattern_manager.h index 1908de5bb4..ceef455347 100644 --- a/plugins/paintops/libpaintop/kis_embedded_pattern_manager.h +++ b/plugins/paintops/libpaintop/kis_embedded_pattern_manager.h @@ -1,38 +1,38 @@ /* * Copyright (c) 2013 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. */ #ifndef __KIS_EMBEDDED_PATTERN_MANAGER_H #define __KIS_EMBEDDED_PATTERN_MANAGER_H #include #include +#include -class KoPattern; class KoAbstractGradient; class PAINTOP_EXPORT KisEmbeddedPatternManager { public: - static void saveEmbeddedPattern(KisPropertiesConfigurationSP setting, const KoPattern *pattern); - static KoPattern* loadEmbeddedPattern(const KisPropertiesConfigurationSP setting); + static void saveEmbeddedPattern(KisPropertiesConfigurationSP setting, const KoPatternSP pattern); + static KoPatternSP loadEmbeddedPattern(const KisPropertiesConfigurationSP setting); private: struct Private; }; #endif /* __KIS_EMBEDDED_PATTERN_MANAGER_H */ diff --git a/plugins/paintops/libpaintop/kis_pressure_gradient_option.cpp b/plugins/paintops/libpaintop/kis_pressure_gradient_option.cpp index 49d104bccc..f0510df834 100644 --- a/plugins/paintops/libpaintop/kis_pressure_gradient_option.cpp +++ b/plugins/paintops/libpaintop/kis_pressure_gradient_option.cpp @@ -1,36 +1,36 @@ /* This file is part of the KDE project * Copyright (C) 2011 Silvio Heinrich * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_pressure_gradient_option.h" #include #include #include #include KisPressureGradientOption::KisPressureGradientOption() : KisCurveOption("Gradient", KisPaintOpOption::GENERAL, false) { } -void KisPressureGradientOption::apply(KoColor& color, const KoAbstractGradient* gradient, const KisPaintInformation& info) const +void KisPressureGradientOption::apply(KoColor& color, const KoAbstractGradientSP gradient, const KisPaintInformation& info) const { if (isChecked() && gradient) { gradient->colorAt(color, computeSizeLikeValue(info)); } } diff --git a/plugins/paintops/libpaintop/kis_pressure_gradient_option.h b/plugins/paintops/libpaintop/kis_pressure_gradient_option.h index 53a61117d5..6940b7f9a1 100644 --- a/plugins/paintops/libpaintop/kis_pressure_gradient_option.h +++ b/plugins/paintops/libpaintop/kis_pressure_gradient_option.h @@ -1,37 +1,39 @@ /* This file is part of the KDE project * Copyright (C) 2011 Silvio Heinrich * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KIS_PRESSURE_GRADIENT_OPTION_H #define KIS_PRESSURE_GRADIENT_OPTION_H +#include + #include "kis_curve_option.h" #include #include class KoColor; -class KoAbstractGradient; + class PAINTOP_EXPORT KisPressureGradientOption: public KisCurveOption { public: KisPressureGradientOption(); - void apply(KoColor& color, const KoAbstractGradient* gradient, const KisPaintInformation& info) const; + void apply(KoColor& color, const KoAbstractGradientSP gradient, const KisPaintInformation& info) const; }; #endif // KIS_PRESSURE_GRADIENT_OPTION_H diff --git a/plugins/paintops/libpaintop/kis_texture_option.cpp b/plugins/paintops/libpaintop/kis_texture_option.cpp index 4a851c23a8..557e36797e 100644 --- a/plugins/paintops/libpaintop/kis_texture_option.cpp +++ b/plugins/paintops/libpaintop/kis_texture_option.cpp @@ -1,273 +1,273 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2012 * Copyright (C) Mohit Goyal , (C) 2014 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kis_texture_option.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_embedded_pattern_manager.h" #include #include "kis_texture_chooser.h" #include KisTextureOption::KisTextureOption() : KisPaintOpOption(KisPaintOpOption::TEXTURE, true) , m_textureOptions(new KisTextureChooser()) { setObjectName("KisTextureOption"); setConfigurationPage(m_textureOptions); - connect(m_textureOptions->textureSelectorWidget, SIGNAL(resourceSelected(KoResource*)), SLOT(resetGUI(KoResource*))); - connect(m_textureOptions->textureSelectorWidget, SIGNAL(resourceSelected(KoResource*)), SLOT(emitSettingChanged())); + connect(m_textureOptions->textureSelectorWidget, SIGNAL(resourceSelected(KoResourceSP )), SLOT(resetGUI(KoResourceSP ))); + connect(m_textureOptions->textureSelectorWidget, SIGNAL(resourceSelected(KoResourceSP )), SLOT(emitSettingChanged())); connect(m_textureOptions->scaleSlider, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_textureOptions->brightnessSlider, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_textureOptions->contrastSlider, SIGNAL(valueChanged(qreal)), SLOT(emitSettingChanged())); connect(m_textureOptions->offsetSliderX, SIGNAL(valueChanged(int)), SLOT(emitSettingChanged())); connect(m_textureOptions->randomOffsetX, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_textureOptions->randomOffsetY, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); connect(m_textureOptions->offsetSliderY, SIGNAL(valueChanged(int)), SLOT(emitSettingChanged())); connect(m_textureOptions->cmbTexturingMode, SIGNAL(currentIndexChanged(int)), SLOT(emitSettingChanged())); connect(m_textureOptions->cmbCutoffPolicy, SIGNAL(currentIndexChanged(int)), SLOT(emitSettingChanged())); connect(m_textureOptions->cutoffSlider, SIGNAL(sigModifiedBlack(int)), SLOT(emitSettingChanged())); connect(m_textureOptions->cutoffSlider, SIGNAL(sigModifiedWhite(int)), SLOT(emitSettingChanged())); connect(m_textureOptions->chkInvert, SIGNAL(toggled(bool)), SLOT(emitSettingChanged())); resetGUI(m_textureOptions->textureSelectorWidget->currentResource()); } KisTextureOption::~KisTextureOption() { delete m_textureOptions; } void KisTextureOption::writeOptionSetting(KisPropertiesConfigurationSP setting) const { m_textureOptions->textureSelectorWidget->blockSignals(true); // Checking if (!m_textureOptions->textureSelectorWidget->currentResource()) return; - KoPattern *pattern = static_cast(m_textureOptions->textureSelectorWidget->currentResource()); + KoPatternSP pattern = m_textureOptions->textureSelectorWidget->currentResource().staticCast(); m_textureOptions->textureSelectorWidget->blockSignals(false); // Checking if (!pattern) return; setting->setProperty("Texture/Pattern/Enabled", isChecked()); if (!isChecked()) { return; } qreal scale = m_textureOptions->scaleSlider->value(); qreal brightness = m_textureOptions->brightnessSlider->value(); qreal contrast = m_textureOptions->contrastSlider->value(); int offsetX = m_textureOptions->offsetSliderX->value(); if (m_textureOptions ->randomOffsetX->isChecked()) { m_textureOptions->offsetSliderX ->setEnabled(false); m_textureOptions->offsetSliderX ->blockSignals(true); m_textureOptions->offsetSliderX ->setValue(offsetX); m_textureOptions->offsetSliderX ->blockSignals(false); } else { m_textureOptions->offsetSliderX ->setEnabled(true); } int offsetY = m_textureOptions->offsetSliderY->value(); if (m_textureOptions ->randomOffsetY->isChecked()) { m_textureOptions->offsetSliderY ->setEnabled(false); m_textureOptions->offsetSliderY ->blockSignals(true); m_textureOptions->offsetSliderY ->setValue(offsetY); m_textureOptions->offsetSliderY ->blockSignals(false); } else { m_textureOptions->offsetSliderY ->setEnabled(true); } int texturingMode = m_textureOptions->cmbTexturingMode->currentIndex(); bool invert = (m_textureOptions->chkInvert->checkState() == Qt::Checked); setting->setProperty("Texture/Pattern/Scale", scale); setting->setProperty("Texture/Pattern/Brightness", brightness); setting->setProperty("Texture/Pattern/Contrast", contrast); setting->setProperty("Texture/Pattern/OffsetX", offsetX); setting->setProperty("Texture/Pattern/OffsetY", offsetY); setting->setProperty("Texture/Pattern/TexturingMode", texturingMode); setting->setProperty("Texture/Pattern/CutoffLeft", m_textureOptions->cutoffSlider->black()); setting->setProperty("Texture/Pattern/CutoffRight", m_textureOptions->cutoffSlider->white()); setting->setProperty("Texture/Pattern/CutoffPolicy", m_textureOptions->cmbCutoffPolicy->currentIndex()); setting->setProperty("Texture/Pattern/Invert", invert); setting->setProperty("Texture/Pattern/MaximumOffsetX",m_textureOptions->offsetSliderX ->maximum()); setting->setProperty("Texture/Pattern/MaximumOffsetY",m_textureOptions->offsetSliderY ->maximum()); setting->setProperty("Texture/Pattern/isRandomOffsetX",m_textureOptions ->randomOffsetX ->isChecked()); setting->setProperty("Texture/Pattern/isRandomOffsetY",m_textureOptions ->randomOffsetY ->isChecked()); KisEmbeddedPatternManager::saveEmbeddedPattern(setting, pattern); } void KisTextureOption::readOptionSetting(const KisPropertiesConfigurationSP setting) { setChecked(setting->getBool("Texture/Pattern/Enabled")); if (!isChecked()) { return; } - KoPattern *pattern = KisEmbeddedPatternManager::loadEmbeddedPattern(setting); + KoPatternSP pattern = KisEmbeddedPatternManager::loadEmbeddedPattern(setting); if (!pattern) { - pattern = static_cast(m_textureOptions->textureSelectorWidget->currentResource()); + pattern =m_textureOptions->textureSelectorWidget->currentResource().staticCast(); } m_textureOptions->textureSelectorWidget->setCurrentPattern(pattern); m_textureOptions->scaleSlider->setValue(setting->getDouble("Texture/Pattern/Scale", 1.0)); m_textureOptions->brightnessSlider->setValue(setting->getDouble("Texture/Pattern/Brightness")); m_textureOptions->contrastSlider->setValue(setting->getDouble("Texture/Pattern/Contrast", 1.0)); m_textureOptions->offsetSliderX->setValue(setting->getInt("Texture/Pattern/OffsetX")); m_textureOptions->offsetSliderY->setValue(setting->getInt("Texture/Pattern/OffsetY")); m_textureOptions->randomOffsetX->setChecked(setting->getBool("Texture/Pattern/isRandomOffsetX")); m_textureOptions->randomOffsetY->setChecked(setting->getBool("Texture/Pattern/isRandomOffsetY")); m_textureOptions->cmbTexturingMode->setCurrentIndex(setting->getInt("Texture/Pattern/TexturingMode", KisTextureProperties::MULTIPLY)); m_textureOptions->cmbCutoffPolicy->setCurrentIndex(setting->getInt("Texture/Pattern/CutoffPolicy")); m_textureOptions->cutoffSlider->slotModifyBlack(setting->getInt("Texture/Pattern/CutoffLeft", 0)); m_textureOptions->cutoffSlider->slotModifyWhite(setting->getInt("Texture/Pattern/CutoffRight", 255)); m_textureOptions->chkInvert->setChecked(setting->getBool("Texture/Pattern/Invert")); } void KisTextureOption::lodLimitations(KisPaintopLodLimitations *l) const { l->limitations << KoID("texture-pattern", i18nc("PaintOp instant preview limitation", "Texture->Pattern (low quality preview)")); } -void KisTextureOption::resetGUI(KoResource* res) +void KisTextureOption::resetGUI(KoResourceSP res) { - KoPattern *pattern = static_cast(res); + KoPatternSP pattern = res.staticCast(); if (!pattern) return; m_textureOptions->offsetSliderX->setRange(0, pattern->pattern().width() / 2); m_textureOptions->offsetSliderY->setRange(0, pattern->pattern().height() / 2); } /**********************************************************************/ /* KisTextureProperties */ /**********************************************************************/ KisTextureProperties::KisTextureProperties(int levelOfDetail) : m_levelOfDetail(levelOfDetail) { } void KisTextureProperties::fillProperties(const KisPropertiesConfigurationSP setting) { if (!setting->hasProperty("Texture/Pattern/PatternMD5")) { m_enabled = false; return; } m_maskInfo = toQShared(new KisTextureMaskInfo(m_levelOfDetail)); if (!m_maskInfo->fillProperties(setting)) { warnKrita << "WARNING: Couldn't load the pattern for a stroke"; m_enabled = false; return; } m_maskInfo = KisTextureMaskInfoCache::instance()->fetchCachedTextureInfo(m_maskInfo); m_enabled = setting->getBool("Texture/Pattern/Enabled", false); m_offsetX = setting->getInt("Texture/Pattern/OffsetX"); m_offsetY = setting->getInt("Texture/Pattern/OffsetY"); m_texturingMode = (TexturingMode) setting->getInt("Texture/Pattern/TexturingMode", MULTIPLY); m_strengthOption.readOptionSetting(setting); m_strengthOption.resetAllSensors(); } void KisTextureProperties::apply(KisFixedPaintDeviceSP dab, const QPoint &offset, const KisPaintInformation & info) { if (!m_enabled) return; KisPaintDeviceSP fillDevice = new KisPaintDevice(KoColorSpaceRegistry::instance()->alpha8()); QRect rect = dab->bounds(); KisPaintDeviceSP mask = m_maskInfo->mask(); const QRect maskBounds = m_maskInfo->maskBounds(); KIS_SAFE_ASSERT_RECOVER_RETURN(mask); int x = offset.x() % maskBounds.width() - m_offsetX; int y = offset.y() % maskBounds.height() - m_offsetY; KisFillPainter fillPainter(fillDevice); fillPainter.fillRect(x - 1, y - 1, rect.width() + 2, rect.height() + 2, mask, maskBounds); fillPainter.end(); qreal pressure = m_strengthOption.apply(info); quint8 *dabData = dab->data(); KisHLineIteratorSP iter = fillDevice->createHLineIteratorNG(x, y, rect.width()); for (int row = 0; row < rect.height(); ++row) { for (int col = 0; col < rect.width(); ++col) { if (m_texturingMode == MULTIPLY) { dab->colorSpace()->multiplyAlpha(dabData, quint8(*iter->oldRawData() * pressure), 1); } else { int pressureOffset = (1.0 - pressure) * 255; qint16 maskA = *iter->oldRawData() + pressureOffset; quint8 dabA = dab->colorSpace()->opacityU8(dabData); dabA = qMax(0, (qint16)dabA - maskA); dab->colorSpace()->setOpacity(dabData, dabA, 1); } iter->nextPixel(); dabData += dab->pixelSize(); } iter->nextRow(); } } diff --git a/plugins/paintops/libpaintop/kis_texture_option.h b/plugins/paintops/libpaintop/kis_texture_option.h index 3100bfc023..1d22b6c271 100644 --- a/plugins/paintops/libpaintop/kis_texture_option.h +++ b/plugins/paintops/libpaintop/kis_texture_option.h @@ -1,97 +1,97 @@ /* This file is part of the KDE project * Copyright (C) Boudewijn Rempt , (C) 2012 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KIS_TEXTURE_OPTION_H #define KIS_TEXTURE_OPTION_H #include #include #include #include "kis_paintop_option.h" #include "kis_pressure_texture_strength_option.h" #include "KisTextureMaskInfo.h" #include class KisTextureChooser; class KoPattern; class KoResource; class KisPropertiesConfiguration; class KisPaintopLodLimitations; class PAINTOP_EXPORT KisTextureOption : public KisPaintOpOption { Q_OBJECT public: explicit KisTextureOption(); ~KisTextureOption() override; public Q_SLOTS: void writeOptionSetting(KisPropertiesConfigurationSP setting) const override; void readOptionSetting(const KisPropertiesConfigurationSP setting) override; void lodLimitations(KisPaintopLodLimitations *l) const override; private Q_SLOTS: - void resetGUI(KoResource*); /// called when a new pattern is selected + void resetGUI(KoResourceSP ); /// called when a new pattern is selected private: /// UI Widget that stores all the texture options KisTextureChooser* m_textureOptions; }; class PAINTOP_EXPORT KisTextureProperties { public: KisTextureProperties(int levelOfDetail); enum TexturingMode { MULTIPLY, SUBTRACT }; bool m_enabled; /** * @brief apply combine the texture map with the dab * @param dab the colored, final representation of the dab, after mirroring and everything. * @param offset the position of the dab on the image. used to calculate the position of the mask pattern */ void apply(KisFixedPaintDeviceSP dab, const QPoint& offset, const KisPaintInformation & info); void fillProperties(const KisPropertiesConfigurationSP setting); private: int m_offsetX; int m_offsetY; TexturingMode m_texturingMode; int m_levelOfDetail; private: KisPressureTextureStrengthOption m_strengthOption; KisTextureMaskInfoSP m_maskInfo; }; #endif // KIS_TEXTURE_OPTION_H diff --git a/plugins/paintops/libpaintop/tests/kis_embedded_pattern_manager_test.cpp b/plugins/paintops/libpaintop/tests/kis_embedded_pattern_manager_test.cpp index d078b587b5..f21820d21e 100644 --- a/plugins/paintops/libpaintop/tests/kis_embedded_pattern_manager_test.cpp +++ b/plugins/paintops/libpaintop/tests/kis_embedded_pattern_manager_test.cpp @@ -1,213 +1,209 @@ /* * Copyright (c) 2013 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_embedded_pattern_manager_test.h" #include #include #include #include #include "kis_embedded_pattern_manager.h" #include #include #include "sdk/tests/kistest.h" -KoPattern *KisEmbeddedPatternManagerTest::createPattern() +KoPatternSP KisEmbeddedPatternManagerTest::createPattern() { QImage image(512, 512, QImage::Format_ARGB32); image.fill(255); QPainter gc(&image); gc.fillRect(100, 100, 312, 312, Qt::red); - KoPattern *pattern = new KoPattern(image, + KoPatternSP pattern (new KoPattern(image, "__test_pattern", - KoResourceServerProvider::instance()->patternServer()->saveLocation()); + KoResourceServerProvider::instance()->patternServer()->saveLocation())); return pattern; } void KisEmbeddedPatternManagerTest::testRoundTrip() { - KoPattern *pattern = createPattern(); + KoPatternSP pattern = createPattern(); KisPropertiesConfigurationSP config(new KisPropertiesConfiguration); KisEmbeddedPatternManager::saveEmbeddedPattern(config, pattern); - KoPattern *newPattern = KisEmbeddedPatternManager::loadEmbeddedPattern(config); + KoPatternSP newPattern = KisEmbeddedPatternManager::loadEmbeddedPattern(config); QCOMPARE(newPattern->pattern(), pattern->pattern()); QCOMPARE(newPattern->name(), pattern->name()); QCOMPARE(QFileInfo(newPattern->filename()).fileName(), QFileInfo(pattern->filename()).fileName()); - delete pattern; - // will be deleted by the server - // delete newPattern; } void KisEmbeddedPatternManagerTest::init() { - Q_FOREACH(KoPattern *pa, KoResourceServerProvider::instance()->patternServer()->resources()) { + Q_FOREACH(KoPatternSP pa, KoResourceServerProvider::instance()->patternServer()->resources()) { if (pa) { KoResourceServerProvider::instance()->patternServer()->removeResourceFile(pa->filename()); } } } KisPropertiesConfigurationSP KisEmbeddedPatternManagerTest::createXML(NameStatus nameStatus, bool hasMd5) { KisPropertiesConfigurationSP setting(new KisPropertiesConfiguration); switch (nameStatus) { case VALID: { setting->setProperty("Texture/Pattern/PatternFileName", "./__test_pattern_path.pat"); setting->setProperty("Texture/Pattern/Name", "__test_pattern"); break; } case PATH: { QString path = KoResourceServerProvider::instance()->patternServer()->saveLocation() + "/__test_pattern.pat"; setting->setProperty("Texture/Pattern/PatternFileName", path); setting->setProperty("Texture/Pattern/Name", "__test_pattern"); break; } case EMPTY: { setting->setProperty("Texture/Pattern/PatternFileName", "./__test_pattern_path.pat"); setting->setProperty("Texture/Pattern/Name", ""); break; } } { - KoPattern *pattern = createPattern(); + KoPatternSP pattern = createPattern(); if (hasMd5) { QByteArray patternMD5 = pattern->md5(); Q_ASSERT(!patternMD5.isEmpty()); setting->setProperty("Texture/Pattern/PatternMD5", patternMD5.toBase64()); } QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); pattern->pattern().save(&buffer, "PNG"); setting->setProperty("Texture/Pattern/Pattern", ba.toBase64()); - delete pattern; } return setting; } -KoPattern* findOnServer(QByteArray md5) +KoPatternSP findOnServer(QByteArray md5) { - KoPattern *pattern = 0; + KoPatternSP pattern; if (!md5.isEmpty()) { return KoResourceServerProvider::instance()->patternServer()->resourceByMD5(md5); } return pattern; } void KisEmbeddedPatternManagerTest::checkOneConfig(NameStatus nameStatus, bool hasMd5, QString expectedName, bool isOnServer) { - QScopedPointer basePattern(createPattern()); + QSharedPointer basePattern(createPattern()); - KoPattern *initialPattern = findOnServer(basePattern->md5()); + KoPatternSP initialPattern = findOnServer(basePattern->md5()); QCOMPARE((bool)initialPattern, isOnServer); KisPropertiesConfigurationSP setting = createXML(nameStatus, hasMd5); - KoPattern *pattern = KisEmbeddedPatternManager::loadEmbeddedPattern(setting); + KoPatternSP pattern = KisEmbeddedPatternManager::loadEmbeddedPattern(setting); QVERIFY(pattern); QCOMPARE(pattern->pattern(), basePattern->pattern()); QVERIFY(pattern->name().startsWith(expectedName)); QFileInfo info(pattern->filename()); QVERIFY(info.baseName().startsWith(expectedName)); QCOMPARE(info.dir().path(), QDir(KoResourceServerProvider::instance()->patternServer()->saveLocation()).path()); // We can only find things on the server by name or by md5; the file path as an identifier does not work. if (isOnServer && nameStatus != EMPTY && !hasMd5) { QCOMPARE(initialPattern, pattern); } // will be deleted by the server // delete pattern; } void KisEmbeddedPatternManagerTest::testLoadingNotOnServerValidName() { checkOneConfig(VALID, false, "__test_pattern", false); } void KisEmbeddedPatternManagerTest::testLoadingNotOnServerEmptyName() { checkOneConfig(EMPTY, false, "__test_pattern_path", false); } void KisEmbeddedPatternManagerTest::testLoadingNotOnServerPathName() { checkOneConfig(PATH, false, "__test_pattern", false); } void KisEmbeddedPatternManagerTest::testLoadingOnServerValidName() { KoResourceServerProvider::instance()->patternServer()->addResource(createPattern(), false); checkOneConfig(VALID, false, "__test_pattern", true); } void KisEmbeddedPatternManagerTest::testLoadingOnServerEmptyName() { KoResourceServerProvider::instance()->patternServer()->addResource(createPattern(), false); checkOneConfig(EMPTY, false, "__test_pattern_path", true); } void KisEmbeddedPatternManagerTest::testLoadingOnServerPathName() { KoResourceServerProvider::instance()->patternServer()->addResource(createPattern(), false); checkOneConfig(PATH, false, "__test_pattern", true); } void KisEmbeddedPatternManagerTest::testLoadingOnServerValidNameMd5() { KoResourceServerProvider::instance()->patternServer()->addResource(createPattern(), true); checkOneConfig(VALID, true, "__test_pattern", true); } void KisEmbeddedPatternManagerTest::testLoadingOnServerEmptyNameMd5() { KoResourceServerProvider::instance()->patternServer()->addResource(createPattern(), true); checkOneConfig(EMPTY, true, "__test_pattern", true); } void KisEmbeddedPatternManagerTest::testLoadingOnServerPathNameMd5() { KoResourceServerProvider::instance()->patternServer()->addResource(createPattern(), false); checkOneConfig(PATH, true, "__test_pattern", true); } KISTEST_MAIN(KisEmbeddedPatternManagerTest) diff --git a/plugins/paintops/libpaintop/tests/kis_embedded_pattern_manager_test.h b/plugins/paintops/libpaintop/tests/kis_embedded_pattern_manager_test.h index 8a363bcbbc..d31963f998 100644 --- a/plugins/paintops/libpaintop/tests/kis_embedded_pattern_manager_test.h +++ b/plugins/paintops/libpaintop/tests/kis_embedded_pattern_manager_test.h @@ -1,60 +1,60 @@ /* * Copyright (c) 2013 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. */ #ifndef __KIS_EMBEDDED_PATTERN_MANAGER_TEST_H #define __KIS_EMBEDDED_PATTERN_MANAGER_TEST_H #include #include -class KoPattern; +#include class KisEmbeddedPatternManagerTest : public QObject { Q_OBJECT private Q_SLOTS: void testRoundTrip(); void init(); void testLoadingNotOnServerValidName(); void testLoadingNotOnServerEmptyName(); void testLoadingNotOnServerPathName(); void testLoadingOnServerValidName(); void testLoadingOnServerEmptyName(); void testLoadingOnServerPathName(); void testLoadingOnServerValidNameMd5(); void testLoadingOnServerEmptyNameMd5(); void testLoadingOnServerPathNameMd5(); private: enum NameStatus { VALID, PATH, EMPTY }; void checkOneConfig(NameStatus nameStatus, bool hasMd5, QString expectedName, bool isOnServer); KisPropertiesConfigurationSP createXML(NameStatus nameStatus, bool hasMd5); - KoPattern *createPattern(); + KoPatternSP createPattern(); }; #endif /* __KIS_EMBEDDED_PATTERN_MANAGER_TEST_H */ diff --git a/plugins/paintops/particle/kis_particle_paintop_settings.cpp b/plugins/paintops/particle/kis_particle_paintop_settings.cpp index 4d3d646d03..ee09ca883d 100644 --- a/plugins/paintops/particle/kis_particle_paintop_settings.cpp +++ b/plugins/paintops/particle/kis_particle_paintop_settings.cpp @@ -1,256 +1,262 @@ /* * Copyright (c) 2010 Lukáš Tvrdý * * 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_particle_paintop_settings.h" #include "kis_particle_paintop_settings_widget.h" #include "kis_particleop_option.h" #include #include struct KisParticlePaintOpSettings::Private { QList uniformProperties; }; KisParticlePaintOpSettings::KisParticlePaintOpSettings() : m_d(new Private) { } KisParticlePaintOpSettings::~KisParticlePaintOpSettings() { } bool KisParticlePaintOpSettings::lodSizeThresholdSupported() const { return false; } bool KisParticlePaintOpSettings::paintIncremental() { return (enumPaintActionType)getInt("PaintOpAction", WASH) == BUILDUP; } #include #include "kis_paintop_preset.h" #include "kis_paintop_settings_update_proxy.h" #include "kis_standard_uniform_properties_factory.h" QList KisParticlePaintOpSettings::uniformProperties(KisPaintOpSettingsSP settings) { QList props = listWeakToStrong(m_d->uniformProperties); if (props.isEmpty()) { { KisIntSliderBasedPaintOpPropertyCallback *prop = new KisIntSliderBasedPaintOpPropertyCallback( KisIntSliderBasedPaintOpPropertyCallback::Int, "particle_particles", i18n("Particles"), settings, 0); prop->setRange(1, 500); prop->setSingleStep(1); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { ParticleOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(int(option.particle_count)); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { ParticleOption option; option.readOptionSetting(prop->settings().data()); option.particle_count = prop->value().toInt(); option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisDoubleSliderBasedPaintOpPropertyCallback *prop = new KisDoubleSliderBasedPaintOpPropertyCallback( KisDoubleSliderBasedPaintOpPropertyCallback::Double, "particle_opecityweight", i18n("Opacity Weight"), settings, 0); prop->setRange(0.01, 1.0); prop->setSingleStep(0.01); prop->setDecimals(2); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { ParticleOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.particle_weight); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { ParticleOption option; option.readOptionSetting(prop->settings().data()); option.particle_weight = prop->value().toReal(); option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisDoubleSliderBasedPaintOpPropertyCallback *prop = new KisDoubleSliderBasedPaintOpPropertyCallback( KisDoubleSliderBasedPaintOpPropertyCallback::Double, "particle_dx_scale", i18n("dx scale"), settings, 0); prop->setRange(-2, 2); prop->setSingleStep(0.01); prop->setDecimals(2); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { ParticleOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.particle_scale_x); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { ParticleOption option; option.readOptionSetting(prop->settings().data()); option.particle_scale_x = prop->value().toReal(); option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisDoubleSliderBasedPaintOpPropertyCallback *prop = new KisDoubleSliderBasedPaintOpPropertyCallback( KisDoubleSliderBasedPaintOpPropertyCallback::Double, "particle_dy_scale", i18n("dy scale"), settings, 0); prop->setRange(-2, 2); prop->setSingleStep(0.01); prop->setDecimals(2); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { ParticleOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.particle_scale_y); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { ParticleOption option; option.readOptionSetting(prop->settings().data()); option.particle_scale_y = prop->value().toReal(); option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisDoubleSliderBasedPaintOpPropertyCallback *prop = new KisDoubleSliderBasedPaintOpPropertyCallback( KisDoubleSliderBasedPaintOpPropertyCallback::Double, "particle_gravity", i18n("Gravity"), settings, 0); prop->setRange(0.01, 1.0); prop->setSingleStep(0.01); prop->setDecimals(2); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { ParticleOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.particle_gravity); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { ParticleOption option; option.readOptionSetting(prop->settings().data()); option.particle_gravity = prop->value().toReal(); option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisIntSliderBasedPaintOpPropertyCallback *prop = new KisIntSliderBasedPaintOpPropertyCallback( KisIntSliderBasedPaintOpPropertyCallback::Int, "particle_iterations", i18n("Iterations"), settings, 0); prop->setRange(1, 300); prop->setSingleStep(1); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { ParticleOption option; option.readOptionSetting(prop->settings().data()); prop->setValue(int(option.particle_iterations)); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { ParticleOption option; option.readOptionSetting(prop->settings().data()); option.particle_iterations = prop->value().toInt(); option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } } { using namespace KisStandardUniformPropertiesFactory; Q_FOREACH (KisUniformPaintOpPropertySP prop, KisPaintOpSettings::uniformProperties(settings)) { if (prop->id() == opacity.id()) { props.prepend(prop); } } } return props; } diff --git a/plugins/paintops/spray/kis_spray_paintop_settings.cpp b/plugins/paintops/spray/kis_spray_paintop_settings.cpp index 2711ffd53d..fba127f2c1 100644 --- a/plugins/paintops/spray/kis_spray_paintop_settings.cpp +++ b/plugins/paintops/spray/kis_spray_paintop_settings.cpp @@ -1,219 +1,222 @@ /* * Copyright (c) 2008,2009,2010 Lukáš Tvrdý * * 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 #include #include #include "kis_spray_paintop_settings.h" #include "kis_sprayop_option.h" #include "kis_spray_shape_option.h" #include struct KisSprayPaintOpSettings::Private { QList uniformProperties; }; KisSprayPaintOpSettings::KisSprayPaintOpSettings() : KisOutlineGenerationPolicy(KisCurrentOutlineFetcher::SIZE_OPTION | KisCurrentOutlineFetcher::ROTATION_OPTION), m_d(new Private) { } KisSprayPaintOpSettings::~KisSprayPaintOpSettings() { } void KisSprayPaintOpSettings::setPaintOpSize(qreal value) { KisSprayOptionProperties option; option.readOptionSetting(this); option.diameter = value; option.writeOptionSetting(this); } qreal KisSprayPaintOpSettings::paintOpSize() const { KisSprayOptionProperties option; option.readOptionSetting(this); return option.diameter; } bool KisSprayPaintOpSettings::paintIncremental() { return (enumPaintActionType)getInt("PaintOpAction", WASH) == BUILDUP; } QPainterPath KisSprayPaintOpSettings::brushOutline(const KisPaintInformation &info, const OutlineMode &mode) { QPainterPath path; if (mode.isVisible) { qreal width = getInt(SPRAY_DIAMETER); qreal height = getInt(SPRAY_DIAMETER) * getDouble(SPRAY_ASPECT); path = ellipseOutline(width, height, getDouble(SPRAY_SCALE), getDouble(SPRAY_ROTATION)); path = outlineFetcher()->fetchOutline(info, this, path, mode); if (mode.forceFullSize) { QPainterPath tiltLine = makeTiltIndicator(info, QPointF(0.0, 0.0), width * 0.5, 3.0); path.addPath(outlineFetcher()->fetchOutline(info, this, tiltLine, mode, 1.0, 0.0, true, 0, 0)); } } return path; } #include #include "kis_paintop_preset.h" #include "kis_paintop_settings_update_proxy.h" #include "kis_standard_uniform_properties_factory.h" QList KisSprayPaintOpSettings::uniformProperties(KisPaintOpSettingsSP settings) { QList props = listWeakToStrong(m_d->uniformProperties); if (props.isEmpty()) { { KisDoubleSliderBasedPaintOpPropertyCallback *prop = new KisDoubleSliderBasedPaintOpPropertyCallback( KisDoubleSliderBasedPaintOpPropertyCallback::Double, "spacing", i18n("Spacing"), settings, 0); prop->setRange(0.01, 10); prop->setSingleStep(0.01); prop->setExponentRatio(3.0); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { KisSprayOptionProperties option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.spacing); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { KisSprayOptionProperties option; option.readOptionSetting(prop->settings().data()); option.spacing = prop->value().toReal(); option.writeOptionSetting(prop->settings().data()); }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisIntSliderBasedPaintOpPropertyCallback *prop = new KisIntSliderBasedPaintOpPropertyCallback( KisIntSliderBasedPaintOpPropertyCallback::Int, "spray_particlecount", i18n("Particle Count"), settings, 0); prop->setRange(0, 1000); prop->setExponentRatio(3); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { KisSprayOptionProperties option; option.readOptionSetting(prop->settings().data()); prop->setValue(int(option.particleCount)); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { KisSprayOptionProperties option; option.readOptionSetting(prop->settings().data()); option.particleCount = prop->value().toInt(); option.writeOptionSetting(prop->settings().data()); }); prop->setIsVisibleCallback( [](const KisUniformPaintOpProperty *prop) { KisSprayOptionProperties option; option.readOptionSetting(prop->settings().data()); return !option.useDensity; }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } { KisDoubleSliderBasedPaintOpPropertyCallback *prop = new KisDoubleSliderBasedPaintOpPropertyCallback( KisDoubleSliderBasedPaintOpPropertyCallback::Double, "spray_density", i18n("Density"), settings, 0); prop->setRange(0.1, 100); prop->setSingleStep(0.01); prop->setDecimals(2); prop->setExponentRatio(3); prop->setSuffix(i18n("%")); prop->setReadCallback( [](KisUniformPaintOpProperty *prop) { KisSprayOptionProperties option; option.readOptionSetting(prop->settings().data()); prop->setValue(option.coverage); }); prop->setWriteCallback( [](KisUniformPaintOpProperty *prop) { KisSprayOptionProperties option; option.readOptionSetting(prop->settings().data()); option.coverage = prop->value().toReal(); option.writeOptionSetting(prop->settings().data()); }); prop->setIsVisibleCallback( [](const KisUniformPaintOpProperty *prop) { KisSprayOptionProperties option; option.readOptionSetting(prop->settings().data()); return option.useDensity; }); - QObject::connect(preset()->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); + KisPaintOpPresetSP p = preset().toStrongRef(); + QObject::connect(p->updateProxy(), SIGNAL(sigSettingsChanged()), prop, SLOT(requestReadValue())); prop->requestReadValue(); props << toQShared(prop); } } { using namespace KisStandardUniformPropertiesFactory; Q_FOREACH (KisUniformPaintOpPropertySP prop, KisPaintOpSettings::uniformProperties(settings)) { if (prop->id() == opacity.id() || prop->id() == size.id()) { props.prepend(prop); } } } return props; } diff --git a/plugins/tools/basictools/kis_tool_colorpicker.cc b/plugins/tools/basictools/kis_tool_colorpicker.cc index c40bb633d4..ebff11d6e4 100644 --- a/plugins/tools/basictools/kis_tool_colorpicker.cc +++ b/plugins/tools/basictools/kis_tool_colorpicker.cc @@ -1,358 +1,358 @@ /* * Copyright (c) 1999 Matthias Elter * Copyright (c) 2002 Patrick Julien * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2018 Emmet & Eoin O'Neill * * 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_tool_colorpicker.h" #include #include #include "kis_cursor.h" #include "KisDocument.h" #include "kis_canvas2.h" #include "KisReferenceImagesLayer.h" #include "KoCanvasBase.h" #include "kis_random_accessor_ng.h" #include "KoResourceServerProvider.h" #include #include "kis_wrapped_rect.h" #include "kis_tool_utils.h" namespace { // GUI ComboBox index constants const int SAMPLE_MERGED = 0; } KisToolColorPicker::KisToolColorPicker(KoCanvasBase *canvas) : KisTool(canvas, KisCursor::pickerCursor()), m_config(new KisToolUtils::ColorPickerConfig) { setObjectName("tool_colorpicker"); m_isActivated = false; m_optionsWidget = 0; m_pickedColor = KoColor(); } KisToolColorPicker::~KisToolColorPicker() { if (m_isActivated) { m_config->save(m_toolActivationSource == KisTool::DefaultActivation); } } void KisToolColorPicker::paint(QPainter &gc, const KoViewConverter &converter) { Q_UNUSED(gc); Q_UNUSED(converter); } void KisToolColorPicker::activate(ToolActivation activation, const QSet &shapes) { m_isActivated = true; m_toolActivationSource = activation; m_config->load(m_toolActivationSource == KisTool::DefaultActivation); updateOptionWidget(); KisTool::activate(activation, shapes); } void KisToolColorPicker::deactivate() { m_config->save(m_toolActivationSource == KisTool::DefaultActivation); m_isActivated = false; KisTool::deactivate(); } bool KisToolColorPicker::pickColor(const QPointF &pos) { // Timer check. if (m_colorPickerDelayTimer.isActive()) { return false; } else { m_colorPickerDelayTimer.setSingleShot(true); m_colorPickerDelayTimer.start(100); } QScopedPointer> imageLocker; m_pickedColor.setOpacity(0.0); // Pick from reference images. if (m_optionsWidget->cmbSources->currentIndex() == SAMPLE_MERGED) { auto *kisCanvas = dynamic_cast(canvas()); KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(kisCanvas, false); KisSharedPtr referenceImageLayer = kisCanvas->imageView()->document()->referenceImagesLayer(); if (referenceImageLayer && kisCanvas->referenceImagesDecoration()->visible()) { QColor color = referenceImageLayer->getPixel(pos); if (color.isValid()) { m_pickedColor.fromQColor(color); } } } if (m_pickedColor.opacityU8() == OPACITY_TRANSPARENT_U8) { if (!currentImage()->bounds().contains(pos.toPoint()) && !currentImage()->wrapAroundModePermitted()) { return false; } KisPaintDeviceSP dev; if (m_optionsWidget->cmbSources->currentIndex() != SAMPLE_MERGED && currentNode() && currentNode()->colorPickSourceDevice()) { dev = currentNode()->colorPickSourceDevice(); } else { imageLocker.reset(new boost::lock_guard(*currentImage())); dev = currentImage()->projection(); } KoColor previousColor = canvas()->resourceManager()->foregroundColor(); KisToolUtils::pickColor(m_pickedColor, dev, pos.toPoint(), &previousColor, m_config->radius, m_config->blend); } if (m_config->updateColor && m_pickedColor.opacityU8() != OPACITY_TRANSPARENT_U8) { KoColor publicColor = m_pickedColor; publicColor.setOpacity(OPACITY_OPAQUE_U8); // Alpha is unwanted for FG and BG colors. if (m_config->toForegroundColor) { canvas()->resourceManager()->setResource(KoCanvasResourceProvider::ForegroundColor, publicColor); } else { canvas()->resourceManager()->setResource(KoCanvasResourceProvider::BackgroundColor, publicColor); } } return true; } void KisToolColorPicker::beginPrimaryAction(KoPointerEvent *event) { bool sampleMerged = m_optionsWidget->cmbSources->currentIndex() == SAMPLE_MERGED; if (!sampleMerged) { if (!currentNode()) { QMessageBox::information(0, i18nc("@title:window", "Krita"), i18n("Cannot pick a color as no layer is active.")); event->ignore(); return; } if (!currentNode()->visible()) { QMessageBox::information(0, i18nc("@title:window", "Krita"), i18n("Cannot pick a color as the active layer is not visible.")); event->ignore(); return; } } QPoint pos = convertToImagePixelCoordFloored(event); setMode(KisTool::PAINT_MODE); bool picked = pickColor(pos); if (!picked) { // Color picking has to start in the visible part of the layer event->ignore(); return; } displayPickedColor(); } void KisToolColorPicker::continuePrimaryAction(KoPointerEvent *event) { CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE); QPoint pos = convertToImagePixelCoordFloored(event); pickColor(pos); displayPickedColor(); } void KisToolColorPicker::endPrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); CHECK_MODE_SANITY_OR_RETURN(KisTool::PAINT_MODE); if (m_config->addPalette) { KisSwatch ent; ent.setColor(m_pickedColor); // We don't ask for a name, too intrusive here - KoColorSet *palette = m_palettes.at(m_optionsWidget->cmbPalette->currentIndex()); + KoColorSetSP palette = m_palettes.at(m_optionsWidget->cmbPalette->currentIndex()); palette->add(ent); if (!palette->save()) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Cannot write to palette file %1. Maybe it is read-only.", palette->filename())); } } } struct PickedChannel { QString name; QString valueText; }; void KisToolColorPicker::displayPickedColor() { if (m_pickedColor.data() && m_optionsWidget) { QList channels = m_pickedColor.colorSpace()->channels(); m_optionsWidget->listViewChannels->clear(); QVector pickedChannels; for (int i = 0; i < channels.count(); ++i) { pickedChannels.append(PickedChannel()); } for (int i = 0; i < channels.count(); ++i) { PickedChannel pc; pc.name = channels[i]->name(); if (m_config->normaliseValues) { pc.valueText = m_pickedColor.colorSpace()->normalisedChannelValueText(m_pickedColor.data(), i); } else { pc.valueText = m_pickedColor.colorSpace()->channelValueText(m_pickedColor.data(), i); } pickedChannels[channels[i]->displayPosition()] = pc; } Q_FOREACH (const PickedChannel &pc, pickedChannels) { QTreeWidgetItem *item = new QTreeWidgetItem(m_optionsWidget->listViewChannels); item->setText(0, pc.name); item->setText(1, pc.valueText); } } } QWidget* KisToolColorPicker::createOptionWidget() { m_optionsWidget = new ColorPickerOptionsWidget(0); m_optionsWidget->setObjectName(toolId() + " option widget"); m_optionsWidget->listViewChannels->setSortingEnabled(false); // See https://bugs.kde.org/show_bug.cgi?id=316896 QWidget *specialSpacer = new QWidget(m_optionsWidget); specialSpacer->setObjectName("SpecialSpacer"); specialSpacer->setFixedSize(0, 0); m_optionsWidget->layout()->addWidget(specialSpacer); // Initialize blend KisSliderSpinBox m_optionsWidget->blend->setRange(0,100); m_optionsWidget->blend->setSuffix("%"); updateOptionWidget(); connect(m_optionsWidget->cbUpdateCurrentColor, SIGNAL(toggled(bool)), SLOT(slotSetUpdateColor(bool))); connect(m_optionsWidget->cbNormaliseValues, SIGNAL(toggled(bool)), SLOT(slotSetNormaliseValues(bool))); connect(m_optionsWidget->cbPalette, SIGNAL(toggled(bool)), SLOT(slotSetAddPalette(bool))); connect(m_optionsWidget->radius, SIGNAL(valueChanged(int)), SLOT(slotChangeRadius(int))); connect(m_optionsWidget->blend, SIGNAL(valueChanged(int)), SLOT(slotChangeBlend(int))); connect(m_optionsWidget->cmbSources, SIGNAL(currentIndexChanged(int)), SLOT(slotSetColorSource(int))); KoResourceServer *srv = KoResourceServerProvider::instance()->paletteServer(); if (!srv) { return m_optionsWidget; } - QList palettes = srv->resources(); + QList palettes = srv->resources(); - Q_FOREACH (KoColorSet *palette, palettes) { + Q_FOREACH (KoColorSetSP palette, palettes) { if (palette) { m_optionsWidget->cmbPalette->addSqueezedItem(palette->name()); m_palettes.append(palette); } } return m_optionsWidget; } void KisToolColorPicker::updateOptionWidget() { if (!m_optionsWidget) return; m_optionsWidget->cbNormaliseValues->setChecked(m_config->normaliseValues); m_optionsWidget->cbUpdateCurrentColor->setChecked(m_config->updateColor); m_optionsWidget->cmbSources->setCurrentIndex(SAMPLE_MERGED + !m_config->sampleMerged); m_optionsWidget->cbPalette->setChecked(m_config->addPalette); m_optionsWidget->radius->setValue(m_config->radius); m_optionsWidget->blend->setValue(m_config->blend); } void KisToolColorPicker::setToForeground(bool newValue) { m_config->toForegroundColor = newValue; emit toForegroundChanged(); } bool KisToolColorPicker::toForeground() const { return m_config->toForegroundColor; } void KisToolColorPicker::slotSetUpdateColor(bool state) { m_config->updateColor = state; } void KisToolColorPicker::slotSetNormaliseValues(bool state) { m_config->normaliseValues = state; displayPickedColor(); } void KisToolColorPicker::slotSetAddPalette(bool state) { m_config->addPalette = state; } void KisToolColorPicker::slotChangeRadius(int value) { m_config->radius = value; } void KisToolColorPicker::slotChangeBlend(int value) { m_config->blend = value; } void KisToolColorPicker::slotSetColorSource(int value) { m_config->sampleMerged = value == SAMPLE_MERGED; } -void KisToolColorPicker::slotAddPalette(KoResource *resource) +void KisToolColorPicker::slotAddPalette(KoResourceSP resource) { - KoColorSet *palette = dynamic_cast(resource); + KoColorSetSP palette = resource.dynamicCast(); if (palette) { m_optionsWidget->cmbPalette->addSqueezedItem(palette->name()); m_palettes.append(palette); } } diff --git a/plugins/tools/basictools/kis_tool_colorpicker.h b/plugins/tools/basictools/kis_tool_colorpicker.h index ce485f1995..75415d625e 100644 --- a/plugins/tools/basictools/kis_tool_colorpicker.h +++ b/plugins/tools/basictools/kis_tool_colorpicker.h @@ -1,142 +1,141 @@ /* * Copyright (c) 1999 Matthias Elter * Copyright (c) 2002 Patrick Julien * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2018 Emmet & Eoin O'Neill * * 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_TOOL_COLOR_PICKER_H_ #define KIS_TOOL_COLOR_PICKER_H_ #include #include "KoToolFactoryBase.h" #include "ui_wdgcolorpicker.h" #include "kis_tool.h" #include -class KoResource; -class KoColorSet; +#include namespace KisToolUtils { struct ColorPickerConfig; } class ColorPickerOptionsWidget : public QWidget, public Ui::ColorPickerOptionsWidget { Q_OBJECT public: ColorPickerOptionsWidget(QWidget *parent) : QWidget(parent) { setupUi(this); } }; class KisToolColorPicker : public KisTool { Q_OBJECT Q_PROPERTY(bool toForeground READ toForeground WRITE setToForeground NOTIFY toForegroundChanged) public: KisToolColorPicker(KoCanvasBase *canvas); ~KisToolColorPicker() override; public: struct Configuration { Configuration(); bool toForegroundColor; bool updateColor; bool addPalette; bool normaliseValues; bool sampleMerged; int radius; int blend; void save(ToolActivation activation) const; void load(ToolActivation activation); }; public: QWidget* createOptionWidget() override; void beginPrimaryAction(KoPointerEvent *event) override; void continuePrimaryAction(KoPointerEvent *event) override; void endPrimaryAction(KoPointerEvent *event) override; void paint(QPainter &gc, const KoViewConverter &converter) override; bool toForeground() const; Q_SIGNALS: void toForegroundChanged(); protected: void activate(ToolActivation activation, const QSet &) override; void deactivate() override; public Q_SLOTS: void setToForeground(bool newValue); void slotSetUpdateColor(bool); void slotSetNormaliseValues(bool); void slotSetAddPalette(bool); void slotChangeRadius(int); void slotChangeBlend(int); - void slotAddPalette(KoResource* resource); + void slotAddPalette(KoResourceSP resource); void slotSetColorSource(int value); private: void displayPickedColor(); bool pickColor(const QPointF& pos); void updateOptionWidget(); // Configuration QScopedPointer m_config; ToolActivation m_toolActivationSource; bool m_isActivated; KoColor m_pickedColor; // Used to skip some tablet events and update color less often QTimer m_colorPickerDelayTimer; ColorPickerOptionsWidget *m_optionsWidget; - QList m_palettes; + QList m_palettes; }; class KisToolColorPickerFactory : public KoToolFactoryBase { public: KisToolColorPickerFactory() : KoToolFactoryBase("KritaSelected/KisToolColorPicker") { setToolTip(i18n("Color Selector Tool")); setSection(TOOL_TYPE_FILL); setPriority(2); setIconName(koIconNameCStr("krita_tool_color_picker")); setShortcut(QKeySequence(Qt::Key_P)); setActivationShapeId(KRITA_TOOL_ACTIVATION_ID); } ~KisToolColorPickerFactory() override {} KoToolBase *createTool(KoCanvasBase *canvas) override { return new KisToolColorPicker(canvas); } }; #endif // KIS_TOOL_COLOR_PICKER_H_ diff --git a/plugins/tools/karbonplugins/tools/KarbonPatternTool.cpp b/plugins/tools/karbonplugins/tools/KarbonPatternTool.cpp index 92af7f974e..e6e0775a07 100644 --- a/plugins/tools/karbonplugins/tools/KarbonPatternTool.cpp +++ b/plugins/tools/karbonplugins/tools/KarbonPatternTool.cpp @@ -1,370 +1,370 @@ /* This file is part of the KDE project * Copyright (C) 2007,2009,2011 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KarbonPatternTool.h" #include "KarbonPatternEditStrategy.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include KarbonPatternTool::KarbonPatternTool(KoCanvasBase *canvas) : KoToolBase(canvas) , m_currentStrategy(0) , m_optionsWidget(0) { } KarbonPatternTool::~KarbonPatternTool() { } void KarbonPatternTool::paint(QPainter &painter, const KoViewConverter &converter) { painter.setBrush(Qt::green); //TODO make configurable painter.setPen(Qt::blue); //TODO make configurable // paint all the strategies Q_FOREACH (KarbonPatternEditStrategyBase *strategy, m_strategies) { if (strategy == m_currentStrategy) { continue; } painter.save(); strategy->paint(painter, converter); painter.restore(); } // paint selected strategy with another color if (m_currentStrategy) { painter.setBrush(Qt::red); //TODO make configurable m_currentStrategy->paint(painter, converter); } } void KarbonPatternTool::repaintDecorations() { Q_FOREACH (KarbonPatternEditStrategyBase *strategy, m_strategies) { canvas()->updateCanvas(strategy->boundingRect()); } } void KarbonPatternTool::mousePressEvent(KoPointerEvent *event) { //m_currentStrategy = 0; Q_FOREACH (KarbonPatternEditStrategyBase *strategy, m_strategies) { if (strategy->selectHandle(event->point, *canvas()->viewConverter())) { m_currentStrategy = strategy; m_currentStrategy->repaint(); useCursor(Qt::SizeAllCursor); break; } } if (m_currentStrategy) { m_currentStrategy->setEditing(true); updateOptionsWidget(); } } void KarbonPatternTool::mouseMoveEvent(KoPointerEvent *event) { if (m_currentStrategy) { m_currentStrategy->repaint(); if (m_currentStrategy->isEditing()) { m_currentStrategy->handleMouseMove(event->point, event->modifiers()); m_currentStrategy->repaint(); return; } } Q_FOREACH (KarbonPatternEditStrategyBase *strategy, m_strategies) { if (strategy->selectHandle(event->point, *canvas()->viewConverter())) { useCursor(Qt::SizeAllCursor); return; } } useCursor(Qt::ArrowCursor); } void KarbonPatternTool::mouseReleaseEvent(KoPointerEvent *event) { Q_UNUSED(event) // if we are editing, get out of edit mode and add a command to the stack if (m_currentStrategy && m_currentStrategy->isEditing()) { m_currentStrategy->setEditing(false); KUndo2Command *cmd = m_currentStrategy->createCommand(); if (cmd) { canvas()->addCommand(cmd); } updateOptionsWidget(); } } void KarbonPatternTool::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_I: { KoDocumentResourceManager *rm = canvas()->shapeController()->resourceManager(); uint handleRadius = rm->handleRadius(); if (event->modifiers() & Qt::ControlModifier) { handleRadius--; } else { handleRadius++; } rm->setHandleRadius(handleRadius); } break; default: event->ignore(); return; } event->accept(); } void KarbonPatternTool::initialize() { if (m_currentStrategy && m_currentStrategy->isEditing()) { return; } QList selectedShapes = canvas()->shapeManager()->selection()->selectedShapes(); // remove all pattern strategies no longer applicable Q_FOREACH (KarbonPatternEditStrategyBase *strategy, m_strategies) { // is this gradient shape still selected ? if (!selectedShapes.contains(strategy->shape()) || ! strategy->shape()->isShapeEditable()) { m_strategies.remove(strategy->shape()); if (m_currentStrategy == strategy) { m_currentStrategy = 0; } delete strategy; continue; } // does the shape has no fill pattern anymore ? QSharedPointer fill = qSharedPointerDynamicCast(strategy->shape()->background()); if (!fill) { // delete the gradient m_strategies.remove(strategy->shape()); if (m_currentStrategy == strategy) { m_currentStrategy = 0; } delete strategy; continue; } strategy->updateHandles(); strategy->repaint(); } KoImageCollection *imageCollection = canvas()->shapeController()->resourceManager()->imageCollection(); // now create new strategies if needed Q_FOREACH (KoShape *shape, selectedShapes) { if (!shape->isShapeEditable()) { continue; } // do we already have a strategy for that shape? if (m_strategies.contains(shape)) { continue; } if (qSharedPointerDynamicCast(shape->background())) { KarbonPatternEditStrategyBase *s = new KarbonOdfPatternEditStrategy(shape, imageCollection); m_strategies.insert(shape, s); s->repaint(); } } // automatically select strategy when editing single shape if (m_strategies.count() == 1 && ! m_currentStrategy) { m_currentStrategy = m_strategies.begin().value(); updateOptionsWidget(); } if (m_currentStrategy) { m_currentStrategy->repaint(); } } void KarbonPatternTool::activate(ToolActivation activation, const QSet &shapes) { KoToolBase::activate(activation, shapes); if (shapes.isEmpty()) { emit done(); return; } initialize(); KarbonPatternEditStrategyBase::setHandleRadius(handleRadius()); KarbonPatternEditStrategyBase::setGrabSensitivity(grabSensitivity()); useCursor(Qt::ArrowCursor); connect(canvas()->shapeManager(), SIGNAL(selectionContentChanged()), this, SLOT(initialize())); } void KarbonPatternTool::deactivate() { // we are not interested in selection content changes when not active disconnect(canvas()->shapeManager(), SIGNAL(selectionContentChanged()), this, SLOT(initialize())); Q_FOREACH (KarbonPatternEditStrategyBase *strategy, m_strategies) { strategy->repaint(); } qDeleteAll(m_strategies); m_strategies.clear(); Q_FOREACH (KoShape *shape, canvas()->shapeManager()->selection()->selectedShapes()) { shape->update(); } m_currentStrategy = 0; KoToolBase::deactivate(); } void KarbonPatternTool::documentResourceChanged(int key, const QVariant &res) { switch (key) { case KoDocumentResourceManager::HandleRadius: Q_FOREACH (KarbonPatternEditStrategyBase *strategy, m_strategies) { strategy->repaint(); } KarbonPatternEditStrategyBase::setHandleRadius(res.toUInt()); Q_FOREACH (KarbonPatternEditStrategyBase *strategy, m_strategies) { strategy->repaint(); } break; case KoDocumentResourceManager::GrabSensitivity: KarbonPatternEditStrategyBase::setGrabSensitivity(res.toUInt()); break; default: return; } } QList > KarbonPatternTool::createOptionWidgets() { QList > widgets; m_optionsWidget = new KarbonPatternOptionsWidget(); connect(m_optionsWidget, SIGNAL(patternChanged()), this, SLOT(patternChanged())); KoResourceServer *rserver = KoResourceServerProvider::instance()->patternServer(); QSharedPointer adapter(new KoResourceServerAdapter(rserver)); KoResourceItemChooser *chooser = new KoResourceItemChooser(adapter, m_optionsWidget); chooser->setObjectName("KarbonPatternChooser"); - connect(chooser, SIGNAL(resourceSelected(KoResource*)), - this, SLOT(patternSelected(KoResource*))); + connect(chooser, SIGNAL(resourceSelected(KoResourceSP )), + this, SLOT(patternSelected(KoResourceSP ))); m_optionsWidget->setWindowTitle(i18n("Pattern Options")); widgets.append(m_optionsWidget); chooser->setWindowTitle(i18n("Patterns")); widgets.append(chooser); updateOptionsWidget(); return widgets; } -void KarbonPatternTool::patternSelected(KoResource *resource) +void KarbonPatternTool::patternSelected(KoResourceSP resource) { - KoPattern *currentPattern = dynamic_cast(resource); + KoPatternSP currentPattern = resource.dynamicCast(); if (!currentPattern || ! currentPattern->valid()) { return; } KoImageCollection *imageCollection = canvas()->shapeController()->resourceManager()->imageCollection(); if (imageCollection) { QList selectedShapes = canvas()->shapeManager()->selection()->selectedShapes(); QSharedPointer newFill(new KoPatternBackground(imageCollection)); newFill->setPattern(currentPattern->pattern()); canvas()->addCommand(new KoShapeBackgroundCommand(selectedShapes, newFill)); initialize(); } } void KarbonPatternTool::updateOptionsWidget() { if (m_optionsWidget && m_currentStrategy) { QSharedPointer fill = qSharedPointerDynamicCast(m_currentStrategy->shape()->background()); if (fill) { m_optionsWidget->setRepeat(fill->repeat()); m_optionsWidget->setReferencePoint(fill->referencePoint()); m_optionsWidget->setReferencePointOffset(fill->referencePointOffset()); m_optionsWidget->setTileRepeatOffset(fill->tileRepeatOffset()); m_optionsWidget->setPatternSize(fill->patternDisplaySize().toSize()); } } } void KarbonPatternTool::patternChanged() { if (m_currentStrategy) { KoShape *shape = m_currentStrategy->shape(); QSharedPointer oldFill = qSharedPointerDynamicCast(shape->background()); if (!oldFill) { return; } KoImageCollection *imageCollection = canvas()->shapeController()->resourceManager()->imageCollection(); if (!imageCollection) { return; } QSharedPointer newFill(new KoPatternBackground(imageCollection)); if (!newFill) { return; } newFill->setTransform(oldFill->transform()); newFill->setPattern(oldFill->pattern()); newFill->setRepeat(m_optionsWidget->repeat()); newFill->setReferencePoint(m_optionsWidget->referencePoint()); newFill->setReferencePointOffset(m_optionsWidget->referencePointOffset()); newFill->setTileRepeatOffset(m_optionsWidget->tileRepeatOffset()); newFill->setPatternDisplaySize(m_optionsWidget->patternSize()); canvas()->addCommand(new KoShapeBackgroundCommand(shape, newFill)); } } diff --git a/plugins/tools/karbonplugins/tools/KarbonPatternTool.h b/plugins/tools/karbonplugins/tools/KarbonPatternTool.h index 0ccddd7b02..85bb46c3ea 100644 --- a/plugins/tools/karbonplugins/tools/KarbonPatternTool.h +++ b/plugins/tools/karbonplugins/tools/KarbonPatternTool.h @@ -1,68 +1,70 @@ /* This file is part of the KDE project * Copyright (C) 2007,2009 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KARBONPATTERNTOOL_H_ #define _KARBONPATTERNTOOL_H_ #include +#include + #include class QPainter; -class KoResource; + class KarbonPatternEditStrategyBase; class KarbonPatternOptionsWidget; class KoShape; class KarbonPatternTool : public KoToolBase { Q_OBJECT public: explicit KarbonPatternTool(KoCanvasBase *canvas); ~KarbonPatternTool() override; void paint(QPainter &painter, const KoViewConverter &converter) override; void repaintDecorations() override; void mousePressEvent(KoPointerEvent *event) override; void mouseMoveEvent(KoPointerEvent *event) override; void mouseReleaseEvent(KoPointerEvent *event) override; void keyPressEvent(QKeyEvent *event) override; void activate(ToolActivation activation, const QSet &shapes) override; void deactivate() override; public Q_SLOTS: void documentResourceChanged(int key, const QVariant &res) override; protected: QList > createOptionWidgets() override; private Q_SLOTS: - void patternSelected(KoResource *resource); + void patternSelected(KoResourceSP resource); void initialize(); /// updates options widget from selected pattern void updateOptionsWidget(); void patternChanged(); private: QMap m_strategies; ///< the list of editing strategies, one for each shape KarbonPatternEditStrategyBase *m_currentStrategy; ///< the current editing strategy KarbonPatternOptionsWidget *m_optionsWidget; }; #endif // _KARBONPATTERNTOOL_H_ diff --git a/plugins/tools/karbonplugins/tools/filterEffectTool/FilterEffectEditWidget.cpp b/plugins/tools/karbonplugins/tools/filterEffectTool/FilterEffectEditWidget.cpp index aa0c771add..812e0bb012 100644 --- a/plugins/tools/karbonplugins/tools/filterEffectTool/FilterEffectEditWidget.cpp +++ b/plugins/tools/karbonplugins/tools/filterEffectTool/FilterEffectEditWidget.cpp @@ -1,558 +1,554 @@ /* This file is part of the KDE project * Copyright (c) 2009 Jan Hambrecht * * 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 * Library General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "FilterEffectEditWidget.h" #include "FilterEffectResource.h" #include "FilterResourceServerProvider.h" #include "FilterInputChangeCommand.h" #include "FilterAddCommand.h" #include "FilterRemoveCommand.h" #include "FilterStackSetCommand.h" #include "KoGenericRegistryModel.h" #include "KoFilterEffectRegistry.h" #include "KoFilterEffect.h" #include "KoFilterEffectStack.h" #include "KoFilterEffectConfigWidgetBase.h" #include "KoFilterEffectFactoryBase.h" #include "KoShape.h" #include "KoCanvasBase.h" #include "KoLegacyResourceModel.h" #include "KoResourceServerAdapter.h" #include #include #include #include #include FilterEffectEditWidget::FilterEffectEditWidget(QWidget *parent) : QWidget(parent) , m_scene(new FilterEffectScene(this)) , m_shape(0) , m_canvas(0) , m_effects(0) { setupUi(this); FilterResourceServerProvider *serverProvider = FilterResourceServerProvider::instance(); KoResourceServer *server = serverProvider->filterEffectServer(); QSharedPointer adapter(new KoResourceServerAdapter(server)); presets->setResourceAdapter(adapter); presets->setDisplayMode(KoResourceSelector::TextMode); presets->setColumnCount(1); - connect(presets, SIGNAL(resourceSelected(KoResource*)), - this, SLOT(presetSelected(KoResource*))); + connect(presets, SIGNAL(resourceSelected(KoResourceSP )), + this, SLOT(presetSelected(KoResourceSP ))); - connect(presets, SIGNAL(resourceApplied(KoResource*)), - this, SLOT(presetSelected(KoResource*))); + connect(presets, SIGNAL(resourceApplied(KoResourceSP )), + this, SLOT(presetSelected(KoResourceSP ))); KoGenericRegistryModel *filterEffectModel = new KoGenericRegistryModel(KoFilterEffectRegistry::instance()); effectSelector->setModel(filterEffectModel); removeEffect->setIcon(koIcon("list-remove")); connect(removeEffect, SIGNAL(clicked()), this, SLOT(removeSelectedItem())); addEffect->setIcon(koIcon("list-add")); addEffect->setToolTip(i18n("Add effect to current filter stack")); connect(addEffect, SIGNAL(clicked()), this, SLOT(addSelectedEffect())); // TODO: make these buttons do something useful raiseEffect->setIcon(koIcon("arrow-up")); raiseEffect->hide(); lowerEffect->setIcon(koIcon("arrow-down")); lowerEffect->hide(); addPreset->setIcon(koIcon("list-add")); addPreset->setToolTip(i18n("Add to filter presets")); connect(addPreset, SIGNAL(clicked()), this, SLOT(addToPresets())); removePreset->setIcon(koIcon("list-remove")); removePreset->setToolTip(i18n("Remove filter preset")); connect(removePreset, SIGNAL(clicked()), this, SLOT(removeFromPresets())); view->setScene(m_scene); view->setRenderHint(QPainter::Antialiasing, true); view->setResizeAnchor(QGraphicsView::AnchorViewCenter); connect(m_scene, SIGNAL(connectionCreated(ConnectionSource,ConnectionTarget)), this, SLOT(connectionCreated(ConnectionSource,ConnectionTarget))); connect(m_scene, SIGNAL(selectionChanged()), this, SLOT(sceneSelectionChanged())); QSet inputs; inputs << ConnectionSource::SourceGraphic; inputs << ConnectionSource::SourceAlpha; inputs << ConnectionSource::BackgroundImage; inputs << ConnectionSource::BackgroundAlpha; inputs << ConnectionSource::FillPaint; inputs << ConnectionSource::StrokePaint; m_defaultSourceSelector = new KComboBox(this); Q_FOREACH (ConnectionSource::SourceType source, inputs) { m_defaultSourceSelector->addItem(ConnectionSource::typeToString(source)); } m_defaultSourceSelector->hide(); m_defaultSourceSelector->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); connect(m_defaultSourceSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(defaultSourceChanged(int))); } FilterEffectEditWidget::~FilterEffectEditWidget() { if (!m_shape) { delete m_effects; } } void FilterEffectEditWidget::editShape(KoShape *shape, KoCanvasBase *canvas) { if (!m_shape) { delete m_effects; m_effects = 0; } m_shape = shape; m_canvas = canvas; if (m_shape) { m_effects = m_shape->filterEffectStack(); } if (!m_effects) { m_effects = new KoFilterEffectStack(); } m_scene->initialize(m_effects); fitScene(); } void FilterEffectEditWidget::fitScene() { QRectF bbox = m_scene->itemsBoundingRect(); m_scene->setSceneRect(bbox); bbox.adjust(-25, -25, 25, 25); view->centerOn(bbox.center()); view->fitInView(bbox, Qt::KeepAspectRatio); } void FilterEffectEditWidget::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); fitScene(); } void FilterEffectEditWidget::showEvent(QShowEvent *event) { Q_UNUSED(event); fitScene(); } void FilterEffectEditWidget::addSelectedEffect() { KoFilterEffectRegistry *registry = KoFilterEffectRegistry::instance(); KoFilterEffectFactoryBase *factory = registry->values()[effectSelector->currentIndex()]; if (!factory) { return; } KoFilterEffect *effect = factory->createFilterEffect(); if (!effect) { return; } if (m_shape) { if (!m_shape->filterEffectStack()) { m_effects->appendFilterEffect(effect); m_canvas->addCommand(new FilterStackSetCommand(m_effects, m_shape)); } else { m_canvas->addCommand(new FilterAddCommand(effect, m_shape)); } } else { m_effects->appendFilterEffect(effect); } m_scene->initialize(m_effects); fitScene(); } void FilterEffectEditWidget::removeSelectedItem() { QList selectedItems = m_scene->selectedEffectItems(); if (!selectedItems.count()) { return; } QList changeData; QList filterEffects = m_effects->filterEffects(); int effectIndexToDelete = -1; const ConnectionSource &item = selectedItems.first(); KoFilterEffect *effect = item.effect(); if (item.type() == ConnectionSource::Effect) { int effectIndex = filterEffects.indexOf(effect); // adjust inputs of all following effects in the stack for (int i = effectIndex + 1; i < filterEffects.count(); ++i) { KoFilterEffect *nextEffect = filterEffects[i]; QList inputs = nextEffect->inputs(); int inputIndex = 0; Q_FOREACH (const QString &input, inputs) { if (input == effect->output()) { InputChangeData data(nextEffect, inputIndex, input, ""); changeData.append(data); } } // if one of the next effects has the same output name we stop if (nextEffect->output() == effect->output()) { break; } } effectIndexToDelete = effectIndex; } else { QString outputName = ConnectionSource::typeToString(item.type()); QList inputs = effect->inputs(); int inputIndex = 0; Q_FOREACH (const QString &input, inputs) { if (input == outputName) { InputChangeData data(effect, inputIndex, input, ""); changeData.append(data); } inputIndex++; } } KUndo2Command *cmd = new KUndo2Command(); if (changeData.count()) { KUndo2Command *subCmd = new FilterInputChangeCommand(changeData, m_shape, cmd); cmd->setText(subCmd->text()); } if (effectIndexToDelete >= 0) { KUndo2Command *subCmd = new FilterRemoveCommand(effectIndexToDelete, m_effects, m_shape, cmd); cmd->setText(subCmd->text()); } if (m_canvas && m_shape) { m_canvas->addCommand(cmd); } else { cmd->redo(); delete cmd; } m_scene->initialize(m_effects); fitScene(); } void FilterEffectEditWidget::connectionCreated(ConnectionSource source, ConnectionTarget target) { QList filterEffects = m_effects->filterEffects(); int targetEffectIndex = filterEffects.indexOf(target.effect()); if (targetEffectIndex < 0) { return; } QList changeData; QString sourceName; if (source.type() == ConnectionSource::Effect) { sourceName = source.effect()->output(); int sourceEffectIndex = filterEffects.indexOf(source.effect()); if (targetEffectIndex - sourceEffectIndex > 1) { // there are effects between source effect and target effect // so we have to take extra care bool renameOutput = false; if (sourceName.isEmpty()) { // output is not named so we have to rename the source output // and adjust the next effect in case it uses this output renameOutput = true; } else { // output is named but if there is an effect with the same // output name, we have to rename the source output for (int i = sourceEffectIndex + 1; i < targetEffectIndex; ++i) { KoFilterEffect *effect = filterEffects[i]; if (effect->output() == sourceName) { renameOutput = true; break; } } } if (renameOutput) { QSet uniqueOutputNames; Q_FOREACH (KoFilterEffect *effect, filterEffects) { uniqueOutputNames.insert(effect->output()); } int index = 0; QString newOutputName; do { newOutputName = QString("result%1").arg(index); } while (uniqueOutputNames.contains(newOutputName)); // rename source output source.effect()->setOutput(newOutputName); // adjust following effects for (int i = sourceEffectIndex + 1; i < targetEffectIndex; ++i) { KoFilterEffect *effect = filterEffects[i]; int inputIndex = 0; Q_FOREACH (const QString &input, effect->inputs()) { if (input.isEmpty() && (i == sourceEffectIndex + 1 || input == sourceName)) { InputChangeData data(effect, inputIndex, input, newOutputName); changeData.append(data); } inputIndex++; } if (sourceName.isEmpty() || effect->output() == sourceName) { break; } } sourceName = newOutputName; } } } else { // source is an predefined input image sourceName = ConnectionSource::typeToString(source.type()); } // finally set the input of the target if (target.inputIndex() >= target.effect()->inputs().count()) { // insert new input here target.effect()->addInput(sourceName); } else { QString oldInput = target.effect()->inputs()[target.inputIndex()]; InputChangeData data(target.effect(), target.inputIndex(), oldInput, sourceName); changeData.append(data); } if (changeData.count()) { KUndo2Command *cmd = new FilterInputChangeCommand(changeData, m_shape); if (m_canvas) { m_canvas->addCommand(cmd); } else { cmd->redo(); delete cmd; } } m_scene->initialize(m_effects); fitScene(); } void FilterEffectEditWidget::addToPresets() { if (!m_effects) { return; } bool ok = false; QString effectName = QInputDialog::getText(this, i18n("Effect name"), i18n("Please enter a name for the filter effect"), QLineEdit::Normal, QString(), &ok); if (!ok) { return; } - FilterEffectResource *resource = FilterEffectResource::fromFilterEffectStack(m_effects); + QSharedPointer resource(FilterEffectResource::fromFilterEffectStack(m_effects)); if (!resource) { return; } resource->setName(effectName); FilterResourceServerProvider *serverProvider = FilterResourceServerProvider::instance(); KoResourceServer *server = serverProvider->filterEffectServer(); QString savePath = server->saveLocation(); int i = 1; QFileInfo fileInfo; do { fileInfo.setFile(savePath + QString("%1.svg").arg(i++, 4, 10, QChar('0'))); } while (fileInfo.exists()); resource->setFilename(fileInfo.filePath()); resource->setValid(true); - - if (!server->addResource(resource)) { - delete resource; - } } void FilterEffectEditWidget::removeFromPresets() { if (!presets->count()) { return; } FilterResourceServerProvider *serverProvider = FilterResourceServerProvider::instance(); if (!serverProvider) { return; } KoResourceServer *server = serverProvider->filterEffectServer(); if (!server) { return; } - FilterEffectResource *resource = server->resources().at(presets->currentIndex()); + QSharedPointer resource = server->resources().at(presets->currentIndex()); if (!resource) { return; } server->removeResourceAndBlacklist(resource); } -void FilterEffectEditWidget::presetSelected(KoResource *resource) +void FilterEffectEditWidget::presetSelected(KoResourceSP resource) { - FilterEffectResource *effectResource = dynamic_cast(resource); + QSharedPointer effectResource = resource.dynamicCast(); if (!effectResource) { return; } KoFilterEffectStack *filterStack = effectResource->toFilterStack(); if (!filterStack) { return; } if (m_shape) { KUndo2Command *cmd = new FilterStackSetCommand(filterStack, m_shape); if (m_canvas) { m_canvas->addCommand(cmd); } else { cmd->redo(); delete cmd; } } else { delete m_effects; } m_effects = filterStack; m_scene->initialize(m_effects); fitScene(); } void FilterEffectEditWidget::addWidgetForItem(ConnectionSource item) { // get the filter effect from the item KoFilterEffect *filterEffect = item.effect(); if (item.type() != ConnectionSource::Effect) { filterEffect = 0; } KoFilterEffect *currentEffect = m_currentItem.effect(); if (m_currentItem.type() != ConnectionSource::Effect) { currentEffect = 0; } m_defaultSourceSelector->hide(); // remove current widget if new effect is zero or effect type has changed if (!filterEffect || !currentEffect || (filterEffect->id() != currentEffect->id())) { while (configStack->count()) { configStack->removeWidget(configStack->widget(0)); } } m_currentItem = item; KoFilterEffectConfigWidgetBase *currentPanel = 0; if (!filterEffect) { if (item.type() != ConnectionSource::Effect) { configStack->insertWidget(0, m_defaultSourceSelector); m_defaultSourceSelector->blockSignals(true); m_defaultSourceSelector->setCurrentIndex(item.type() - 1); m_defaultSourceSelector->blockSignals(false); m_defaultSourceSelector->show(); } } else if (!currentEffect || currentEffect->id() != filterEffect->id()) { // when a shape is set and is differs from the previous one // get the config widget and insert it into the option widget KoFilterEffectRegistry *registry = KoFilterEffectRegistry::instance(); KoFilterEffectFactoryBase *factory = registry->value(filterEffect->id()); if (!factory) { return; } currentPanel = factory->createConfigWidget(); if (!currentPanel) { return; } configStack->insertWidget(0, currentPanel); connect(currentPanel, SIGNAL(filterChanged()), this, SLOT(filterChanged())); } currentPanel = qobject_cast(configStack->widget(0)); if (currentPanel) { currentPanel->editFilterEffect(filterEffect); } } void FilterEffectEditWidget::filterChanged() { if (m_shape) { m_shape->update(); } } void FilterEffectEditWidget::sceneSelectionChanged() { QList selectedItems = m_scene->selectedEffectItems(); if (!selectedItems.count()) { addWidgetForItem(ConnectionSource()); } else { addWidgetForItem(selectedItems.first()); } } void FilterEffectEditWidget::defaultSourceChanged(int index) { if (m_currentItem.type() == ConnectionSource::Effect) { return; } KoFilterEffect *filterEffect = m_currentItem.effect(); if (!filterEffect) { return; } QString oldInput = ConnectionSource::typeToString(m_currentItem.type()); QString newInput = m_defaultSourceSelector->itemText(index); const QString defInput = "SourceGraphic"; int effectIndex = m_effects->filterEffects().indexOf(filterEffect); InputChangeData data; int inputIndex = 0; Q_FOREACH (const QString &input, filterEffect->inputs()) { if (input == oldInput || (effectIndex == 0 && oldInput == defInput)) { data = InputChangeData(filterEffect, inputIndex, input, newInput); break; } inputIndex++; } KUndo2Command *cmd = new FilterInputChangeCommand(data, m_shape); if (m_canvas && m_shape) { m_canvas->addCommand(cmd); } else { cmd->redo(); delete cmd; } m_scene->initialize(m_effects); fitScene(); } diff --git a/plugins/tools/karbonplugins/tools/filterEffectTool/FilterEffectEditWidget.h b/plugins/tools/karbonplugins/tools/filterEffectTool/FilterEffectEditWidget.h index d2a76bb65f..956254e3fe 100644 --- a/plugins/tools/karbonplugins/tools/filterEffectTool/FilterEffectEditWidget.h +++ b/plugins/tools/karbonplugins/tools/filterEffectTool/FilterEffectEditWidget.h @@ -1,71 +1,71 @@ /* This file is part of the KDE project * Copyright (c) 2009 Jan Hambrecht * * 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 * Library General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef FILTEREFFECTEDITWIDGET_H #define FILTEREFFECTEDITWIDGET_H #include "ui_FilterEffectEditWidget.h" #include "FilterEffectScene.h" #include #include #include class KoShape; class KoFilterEffect; class KoFilterEffectStack; class FilterEffectEditWidget : public QWidget, Ui::FilterEffectEditWidget { Q_OBJECT public: explicit FilterEffectEditWidget(QWidget *parent = 0); ~FilterEffectEditWidget() override; /// Edits effects of given shape void editShape(KoShape *shape, KoCanvasBase *canvas); protected: /// reimplemented from QWidget void resizeEvent(QResizeEvent *event) override; /// reimplemented from QWidget void showEvent(QShowEvent *event) override; private Q_SLOTS: void addSelectedEffect(); void removeSelectedItem(); void connectionCreated(ConnectionSource source, ConnectionTarget target); void addToPresets(); void removeFromPresets(); - void presetSelected(KoResource *resource); + void presetSelected(KoResourceSP resource); void filterChanged(); void sceneSelectionChanged(); void defaultSourceChanged(int); private: void fitScene(); void addWidgetForItem(ConnectionSource item); FilterEffectScene *m_scene; KoShape *m_shape; QPointer m_canvas; KoFilterEffectStack *m_effects; ConnectionSource m_currentItem; KComboBox *m_defaultSourceSelector; }; #endif // FILTEREFFECTEDITWIDGET_H diff --git a/plugins/tools/karbonplugins/tools/filterEffectTool/KarbonFilterEffectsTool.cpp b/plugins/tools/karbonplugins/tools/filterEffectTool/KarbonFilterEffectsTool.cpp index 5a92a591e0..94e9139b1d 100644 --- a/plugins/tools/karbonplugins/tools/filterEffectTool/KarbonFilterEffectsTool.cpp +++ b/plugins/tools/karbonplugins/tools/filterEffectTool/KarbonFilterEffectsTool.cpp @@ -1,554 +1,556 @@ /* This file is part of the KDE project * Copyright (c) 2009-2011 Jan Hambrecht * * 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 * Library General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KarbonFilterEffectsTool.h" #include "KoFilterEffect.h" #include "KoFilterEffectStack.h" #include "KoFilterEffectFactoryBase.h" #include "KoFilterEffectRegistry.h" #include "KoFilterEffectConfigWidgetBase.h" #include "KoCanvasBase.h" #include "KoDocumentResourceManager.h" #include "KoSelectedShapesProxy.h" #include "KoViewConverter.h" #include "KoSelection.h" #include "FilterEffectEditWidget.h" #include "FilterEffectResource.h" #include "FilterResourceServerProvider.h" #include "FilterStackSetCommand.h" #include "FilterRegionChangeCommand.h" #include "FilterRegionEditStrategy.h" #include "KoResourceServerAdapter.h" #include "KoResourceSelector.h" #include #include #include #include #include +#include #include +#include #include #include #include #include #include #include #include #include #include "kis_double_parse_spin_box.h" class KarbonFilterEffectsTool::Private { public: Private() : filterSelector(0) , configSelector(0) , configStack(0) , posX(0) , posY(0) , posW(0) , posH(0) , clearButton(0) , currentEffect(0) , currentPanel(0) , currentShape(0) { } void fillConfigSelector(KoShape *shape, KarbonFilterEffectsTool *tool) { if (!configSelector) { return; } configSelector->clear(); clearButton->setEnabled(false); if (!shape || !shape->filterEffectStack()) { addWidgetForEffect(0, tool); return; } configSelector->blockSignals(true); int index = 0; Q_FOREACH (KoFilterEffect *effect, shape->filterEffectStack()->filterEffects()) { configSelector->addItem(QString("%1 - ").arg(index) + effect->name()); index++; } configSelector->blockSignals(false); KoFilterEffect *effect = index > 0 ? shape->filterEffectStack()->filterEffects().first() : 0; addWidgetForEffect(effect, tool); clearButton->setEnabled(shape->filterEffectStack() != 0); } void addWidgetForEffect(KoFilterEffect *filterEffect, KarbonFilterEffectsTool *tool) { // remove current widget if new effect is zero or effect type has changed if (!filterEffect || (currentEffect && filterEffect->id() != currentEffect->id())) { while (configStack->count()) { configStack->removeWidget(configStack->widget(0)); } } if (!filterEffect) { currentEffect = 0; currentPanel = 0; } else if (!currentEffect || currentEffect->id() != filterEffect->id()) { // when a effect is set and is differs from the previous one // get the config widget and insert it into the option widget currentEffect = filterEffect; KoFilterEffectRegistry *registry = KoFilterEffectRegistry::instance(); KoFilterEffectFactoryBase *factory = registry->value(currentEffect->id()); if (!factory) { return; } currentPanel = factory->createConfigWidget(); if (!currentPanel) { return; } currentPanel->layout()->setContentsMargins(0, 0, 0, 0); configStack->insertWidget(0, currentPanel); configStack->layout()->setContentsMargins(0, 0, 0, 0); connect(currentPanel, SIGNAL(filterChanged()), tool, SLOT(filterChanged())); } if (currentPanel) { currentPanel->editFilterEffect(filterEffect); } updateFilterRegion(); } void updateFilterRegion() { QRectF region = currentEffect ? currentEffect->filterRect() : QRectF(0, 0, 0, 0); posX->blockSignals(true); posX->setValue(100.0 * region.x()); posX->blockSignals(false); posX->setEnabled(currentEffect != 0); posY->blockSignals(true); posY->setValue(100.0 * region.y()); posY->blockSignals(false); posY->setEnabled(currentEffect != 0); posW->blockSignals(true); posW->setValue(100.0 * region.width()); posW->blockSignals(false); posW->setEnabled(currentEffect != 0); posH->blockSignals(true); posH->setValue(100.0 * region.height()); posH->blockSignals(false); posH->setEnabled(currentEffect != 0); } EditMode editModeFromMousePosition(const QPointF &mousePosition, KarbonFilterEffectsTool *tool) { if (currentShape && currentShape->filterEffectStack() && currentEffect) { // get the size rect of the shape QRectF sizeRect(QPointF(), currentShape->size()); // get the filter rectangle in shape coordinates QRectF filterRect = currentEffect->filterRectForBoundingRect(sizeRect); // get the transformation from document to shape coordinates QTransform transform = currentShape->absoluteTransformation(0).inverted(); // adjust filter rectangle by grab sensitivity const int grabDistance = tool->grabSensitivity(); QPointF border = tool->canvas()->viewConverter()->viewToDocument(QPointF(grabDistance, grabDistance)); filterRect.adjust(-border.x(), -border.y(), border.x(), border.y()); // map event point from document to shape coordinates QPointF shapePoint = transform.map(mousePosition); // check if the mouse is inside/near our filter rect if (filterRect.contains(shapePoint)) { if (qAbs(shapePoint.x() - filterRect.left()) <= border.x()) { return MoveLeft; } else if (qAbs(shapePoint.x() - filterRect.right()) <= border.x()) { return MoveRight; } else if (qAbs(shapePoint.y() - filterRect.top()) <= border.y()) { return MoveTop; } else if (qAbs(shapePoint.y() - filterRect.bottom()) <= border.y()) { return MoveBottom; } else { return MoveAll; } } else { return None; } } return None; } KoResourceSelector *filterSelector; KComboBox *configSelector; QStackedWidget *configStack; QDoubleSpinBox *posX; QDoubleSpinBox *posY; QDoubleSpinBox *posW; QDoubleSpinBox *posH; QToolButton *clearButton; KoFilterEffect *currentEffect; KoFilterEffectConfigWidgetBase *currentPanel; KoShape *currentShape; }; KarbonFilterEffectsTool::KarbonFilterEffectsTool(KoCanvasBase *canvas) : KoInteractionTool(canvas) , d(new Private()) { connect(canvas->selectedShapesProxy(), SIGNAL(selectionChanged()), this, SLOT(selectionChanged())); connect(canvas->selectedShapesProxy(), SIGNAL(selectionContentChanged()), this, SLOT(selectionChanged())); } KarbonFilterEffectsTool::~KarbonFilterEffectsTool() { delete d; } void KarbonFilterEffectsTool::paint(QPainter &painter, const KoViewConverter &converter) { if (d->currentShape && d->currentShape->filterEffectStack()) { painter.save(); // apply the shape transformation QTransform transform = d->currentShape->absoluteTransformation(&converter); painter.setTransform(transform, true); // apply the zoom transformation KoShape::applyConversion(painter, converter); // get the size rect of the shape QRectF sizeRect(QPointF(), d->currentShape->size()); // get the clipping rect of the filter stack KoFilterEffectStack *filterStack = d->currentShape->filterEffectStack(); QRectF clipRect = filterStack->clipRectForBoundingRect(sizeRect); // finally paint the clipping rect painter.setBrush(Qt::NoBrush); painter.setPen(Qt::blue); painter.drawRect(clipRect); if (currentStrategy()) { currentStrategy()->paint(painter, converter); } else if (d->currentEffect) { QRectF filterRect = d->currentEffect->filterRectForBoundingRect(sizeRect); // paint the filter subregion rect painter.setBrush(Qt::NoBrush); painter.setPen(Qt::red); painter.drawRect(filterRect); } painter.restore(); } } void KarbonFilterEffectsTool::repaintDecorations() { if (d->currentShape && d->currentShape->filterEffectStack()) { QRectF bb = d->currentShape->boundingRect(); const int radius = handleRadius(); canvas()->updateCanvas(bb.adjusted(-radius, -radius, radius, radius)); } } void KarbonFilterEffectsTool::activate(ToolActivation toolActivation, const QSet &shapes) { Q_UNUSED(toolActivation); if (shapes.isEmpty()) { emit done(); return; } d->currentShape = canvas()->selectedShapesProxy()->selection()->firstSelectedShape(); d->fillConfigSelector(d->currentShape, this); } void KarbonFilterEffectsTool::mouseMoveEvent(KoPointerEvent *event) { if (currentStrategy()) { KoInteractionTool::mouseMoveEvent(event); } else { EditMode mode = d->editModeFromMousePosition(event->point, this); switch (mode) { case MoveAll: useCursor(Qt::SizeAllCursor); break; case MoveLeft: case MoveRight: useCursor(Qt::SizeHorCursor); break; case MoveTop: case MoveBottom: useCursor(Qt::SizeVerCursor); break; case None: useCursor(Qt::ArrowCursor); break; } } } KoInteractionStrategy *KarbonFilterEffectsTool::createStrategy(KoPointerEvent *event) { EditMode mode = d->editModeFromMousePosition(event->point, this); if (mode == None) { return 0; } return new FilterRegionEditStrategy(this, d->currentShape, d->currentEffect, mode); } -void KarbonFilterEffectsTool::presetSelected(KoResource *resource) +void KarbonFilterEffectsTool::presetSelected(KoResourceSP resource) { if (!d->currentShape) { return; } - FilterEffectResource *effectResource = dynamic_cast(resource); + QSharedPointer effectResource = resource.dynamicCast(); if (!effectResource) { return; } KoFilterEffectStack *filterStack = effectResource->toFilterStack(); if (!filterStack) { return; } canvas()->addCommand(new FilterStackSetCommand(filterStack, d->currentShape)); d->fillConfigSelector(d->currentShape, this); } void KarbonFilterEffectsTool::editFilter() { QPointer dlg = new QDialog(); dlg->setWindowTitle(i18n("Filter Effect Editor")); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); QWidget *mainWidget = new QWidget(0); QVBoxLayout *mainLayout = new QVBoxLayout; dlg->setLayout(mainLayout); mainLayout->addWidget(mainWidget); connect(buttonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()), dlg, SLOT(close())); FilterEffectEditWidget *editor = new FilterEffectEditWidget(dlg); editor->editShape(d->currentShape, canvas()); mainLayout->addWidget(editor); mainLayout->addWidget(buttonBox); dlg->exec(); delete dlg; d->fillConfigSelector(d->currentShape, this); } void KarbonFilterEffectsTool::clearFilter() { if (!d->currentShape) { return; } if (!d->currentShape->filterEffectStack()) { return; } canvas()->addCommand(new FilterStackSetCommand(0, d->currentShape)); d->fillConfigSelector(d->currentShape, this); } void KarbonFilterEffectsTool::filterChanged() { if (!d->currentShape) { return; } d->currentShape->update(); } void KarbonFilterEffectsTool::filterSelected(int index) { if (!d->currentShape || ! d->currentShape->filterEffectStack()) { return; } KoFilterEffect *effect = 0; QList filterEffects = d->currentShape->filterEffectStack()->filterEffects(); if (index >= 0 && index < filterEffects.count()) { effect = filterEffects[index]; } d->addWidgetForEffect(effect, this); repaintDecorations(); } void KarbonFilterEffectsTool::selectionChanged() { d->currentShape = canvas()->selectedShapesProxy()->selection()->firstSelectedShape(); d->fillConfigSelector(d->currentShape, this); } void KarbonFilterEffectsTool::regionXChanged(double x) { if (!d->currentEffect) { return; } QRectF region = d->currentEffect->filterRect(); region.setX(x / 100.0); canvas()->addCommand(new FilterRegionChangeCommand(d->currentEffect, region, d->currentShape)); } void KarbonFilterEffectsTool::regionYChanged(double y) { if (!d->currentEffect) { return; } QRectF region = d->currentEffect->filterRect(); region.setY(y / 100.0); canvas()->addCommand(new FilterRegionChangeCommand(d->currentEffect, region, d->currentShape)); } void KarbonFilterEffectsTool::regionWidthChanged(double width) { if (!d->currentEffect) { return; } QRectF region = d->currentEffect->filterRect(); region.setWidth(width / 100.0); canvas()->addCommand(new FilterRegionChangeCommand(d->currentEffect, region, d->currentShape)); } void KarbonFilterEffectsTool::regionHeightChanged(double height) { if (!d->currentEffect) { return; } QRectF region = d->currentEffect->filterRect(); region.setHeight(height / 100.0); canvas()->addCommand(new FilterRegionChangeCommand(d->currentEffect, region, d->currentShape)); } QList > KarbonFilterEffectsTool::createOptionWidgets() { QList > widgets; FilterResourceServerProvider *serverProvider = FilterResourceServerProvider::instance(); KoResourceServer *server = serverProvider->filterEffectServer(); QSharedPointer adapter(new KoResourceServerAdapter(server)); //--------------------------------------------------------------------- QWidget *addFilterWidget = new QWidget(); addFilterWidget->setObjectName("AddEffect"); QGridLayout *addFilterLayout = new QGridLayout(addFilterWidget); d->filterSelector = new KoResourceSelector(addFilterWidget); d->filterSelector->setResourceAdapter(adapter); d->filterSelector->setDisplayMode(KoResourceSelector::TextMode); d->filterSelector->setColumnCount(1); addFilterLayout->addWidget(new QLabel(i18n("Effects"), addFilterWidget), 0, 0); addFilterLayout->addWidget(d->filterSelector, 0, 1); - connect(d->filterSelector, SIGNAL(resourceSelected(KoResource*)), - this, SLOT(presetSelected(KoResource*))); + connect(d->filterSelector, SIGNAL(resourceSelected(KoResourceSP )), + this, SLOT(presetSelected(KoResourceSP ))); - connect(d->filterSelector, SIGNAL(resourceApplied(KoResource*)), - this, SLOT(presetSelected(KoResource*))); + connect(d->filterSelector, SIGNAL(resourceApplied(KoResourceSP )), + this, SLOT(presetSelected(KoResourceSP ))); QToolButton *editButton = new QToolButton(addFilterWidget); editButton->setIcon(koIcon("view-filter")); editButton->setToolTip(i18n("View and edit filter")); addFilterLayout->addWidget(editButton, 0, 2); connect(editButton, SIGNAL(clicked()), this, SLOT(editFilter())); d->clearButton = new QToolButton(addFilterWidget); d->clearButton->setIcon(koIcon("edit-delete")); d->clearButton->setToolTip(i18n("Remove filter from object")); addFilterLayout->addWidget(d->clearButton, 0, 3); connect(d->clearButton, SIGNAL(clicked()), this, SLOT(clearFilter())); addFilterWidget->setWindowTitle(i18n("Add Filter")); widgets.append(addFilterWidget); //--------------------------------------------------------------------- QWidget *configFilterWidget = new QWidget(); configFilterWidget->setObjectName("ConfigEffect"); QGridLayout *configFilterLayout = new QGridLayout(configFilterWidget); d->configSelector = new KComboBox(configFilterWidget); configFilterLayout->addWidget(d->configSelector, 0, 0); connect(d->configSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(filterSelected(int))); d->configStack = new QStackedWidget(configFilterWidget); configFilterLayout->addWidget(d->configStack, 1, 0); configFilterLayout->setContentsMargins(0, 0, 0, 0); configFilterWidget->setWindowTitle(i18n("Effect Properties")); widgets.append(configFilterWidget); //--------------------------------------------------------------------- QWidget *filterRegionWidget = new QWidget(); filterRegionWidget->setObjectName("EffectRegion"); QGridLayout *filterRegionLayout = new QGridLayout(filterRegionWidget); d->posX = new KisDoubleParseSpinBox(filterRegionWidget); d->posX->setSuffix("%"); connect(d->posX, SIGNAL(valueChanged(double)), this, SLOT(regionXChanged(double))); filterRegionLayout->addWidget(new QLabel(i18n("X:")), 0, 0); filterRegionLayout->addWidget(d->posX, 0, 1); d->posY = new KisDoubleParseSpinBox(filterRegionWidget); d->posY->setSuffix("%"); connect(d->posY, SIGNAL(valueChanged(double)), this, SLOT(regionYChanged(double))); filterRegionLayout->addWidget(new QLabel(i18n("Y:")), 1, 0); filterRegionLayout->addWidget(d->posY, 1, 1); d->posW = new KisDoubleParseSpinBox(filterRegionWidget); d->posW->setSuffix("%"); connect(d->posW, SIGNAL(valueChanged(double)), this, SLOT(regionWidthChanged(double))); filterRegionLayout->addWidget(new QLabel(i18n("W:")), 0, 2); filterRegionLayout->addWidget(d->posW, 0, 3); d->posH = new KisDoubleParseSpinBox(filterRegionWidget); d->posH->setSuffix("%"); connect(d->posH, SIGNAL(valueChanged(double)), this, SLOT(regionHeightChanged(double))); filterRegionLayout->addWidget(new QLabel(i18n("H:")), 1, 2); filterRegionLayout->addWidget(d->posH, 1, 3); filterRegionLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding), 2, 0); filterRegionLayout->setContentsMargins(0, 0, 0, 0); filterRegionWidget->setWindowTitle(i18n("Effect Region")); widgets.append(filterRegionWidget); //--------------------------------------------------------------------- d->fillConfigSelector(d->currentShape, this); return widgets; } diff --git a/plugins/tools/karbonplugins/tools/filterEffectTool/KarbonFilterEffectsTool.h b/plugins/tools/karbonplugins/tools/filterEffectTool/KarbonFilterEffectsTool.h index 965e3b17cd..0ce5fef917 100644 --- a/plugins/tools/karbonplugins/tools/filterEffectTool/KarbonFilterEffectsTool.h +++ b/plugins/tools/karbonplugins/tools/filterEffectTool/KarbonFilterEffectsTool.h @@ -1,75 +1,76 @@ /* This file is part of the KDE project * Copyright (c) 2009-2010 Jan Hambrecht * * 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 * Library General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KARBONFILTEREFFECTSTOOL_H #define KARBONFILTEREFFECTSTOOL_H #include "KoInteractionTool.h" -class KoResource; +#include + class KoInteractionStrategy; class KarbonFilterEffectsTool : public KoInteractionTool { Q_OBJECT public: enum EditMode { None, MoveAll, MoveLeft, MoveRight, MoveTop, MoveBottom }; explicit KarbonFilterEffectsTool(KoCanvasBase *canvas); ~KarbonFilterEffectsTool() override; /// reimplemented from KoToolBase void paint(QPainter &painter, const KoViewConverter &converter) override; /// reimplemented from KoToolBase void repaintDecorations() override; /// reimplemented from KoToolBase void mouseMoveEvent(KoPointerEvent *event) override; /// reimplemented from KoToolBase void activate(ToolActivation toolActivation, const QSet &shapes) override; protected: /// reimplemented from KoToolBase QList > createOptionWidgets() override; /// reimplemented from KoToolBase KoInteractionStrategy *createStrategy(KoPointerEvent *event) override; private Q_SLOTS: void editFilter(); void clearFilter(); void filterChanged(); void filterSelected(int index); void selectionChanged(); - void presetSelected(KoResource *resource); + void presetSelected(KoResourceSP resource); void regionXChanged(double x); void regionYChanged(double y); void regionWidthChanged(double width); void regionHeightChanged(double height); private: class Private; Private *const d; }; #endif // KARBONFILTEREFFECTSTOOL_H diff --git a/plugins/tools/tool_lazybrush/kis_tool_lazy_brush_options_widget.cpp b/plugins/tools/tool_lazybrush/kis_tool_lazy_brush_options_widget.cpp index 0d81311997..90574c1ed7 100644 --- a/plugins/tools/tool_lazybrush/kis_tool_lazy_brush_options_widget.cpp +++ b/plugins/tools/tool_lazybrush/kis_tool_lazy_brush_options_widget.cpp @@ -1,379 +1,379 @@ /* * Copyright (c) 2016 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_tool_lazy_brush_options_widget.h" #include "ui_kis_tool_lazy_brush_options_widget.h" #include #include "KisPaletteModel.h" #include "kis_config.h" #include #include "kis_canvas_resource_provider.h" #include "kis_signal_auto_connection.h" #include "lazybrush/kis_colorize_mask.h" #include "kis_image.h" #include "kis_signals_blocker.h" #include "kis_signal_compressor.h" #include "kis_layer_properties_icons.h" struct KisToolLazyBrushOptionsWidget::Private { Private() : baseNodeChangedCompressor(500, KisSignalCompressor::FIRST_ACTIVE) { } Ui_KisToolLazyBrushOptionsWidget *ui; KisPaletteModel *colorModel; KisCanvasResourceProvider *provider; KisSignalAutoConnectionsStore providerSignals; KisSignalAutoConnectionsStore maskSignals; KisColorizeMaskSP activeMask; - KoColorSet colorSet; + KoColorSetSP colorSet {new KoColorSet(QString())}; int transparentColorIndex; KisSignalCompressor baseNodeChangedCompressor; }; KisToolLazyBrushOptionsWidget::KisToolLazyBrushOptionsWidget(KisCanvasResourceProvider *provider, QWidget *parent) : QWidget(parent), m_d(new Private) { m_d->ui = new Ui_KisToolLazyBrushOptionsWidget(); m_d->ui->setupUi(this); m_d->colorModel = new KisPaletteModel(this); m_d->ui->colorView->setPaletteModel(m_d->colorModel); m_d->ui->colorView->setAllowModification(false); //people proly shouldn't be able to edit the colorentries themselves. m_d->ui->colorView->setCrossedKeyword("transparent"); connect(m_d->ui->chkUseEdgeDetection, SIGNAL(toggled(bool)), SLOT(slotUseEdgeDetectionChanged(bool))); connect(m_d->ui->intEdgeDetectionSize, SIGNAL(valueChanged(int)), SLOT(slotEdgeDetectionSizeChanged(int))); connect(m_d->ui->intRadius, SIGNAL(valueChanged(int)), SLOT(slotRadiusChanged(int))); connect(m_d->ui->intCleanUp, SIGNAL(valueChanged(int)), SLOT(slotCleanUpChanged(int))); connect(m_d->ui->chkLimitToDevice, SIGNAL(toggled(bool)), SLOT(slotLimitToDeviceChanged(bool))); m_d->ui->intEdgeDetectionSize->setRange(0, 100); m_d->ui->intEdgeDetectionSize->setExponentRatio(2.0); m_d->ui->intEdgeDetectionSize->setSuffix(i18n(" px")); m_d->ui->intEdgeDetectionSize->setPrefix(i18n("Edge detection: ")); m_d->ui->intEdgeDetectionSize->setToolTip( i18nc("@info:tooltip", "Activate for images with vast solid areas. " "Set the value to the width of the thinnest " "lines on the image")); m_d->ui->intRadius->setRange(0, 1000); m_d->ui->intRadius->setExponentRatio(3.0); m_d->ui->intRadius->setSuffix(i18n(" px")); m_d->ui->intRadius->setPrefix(i18n("Gap close hint: ")); m_d->ui->intRadius->setToolTip( i18nc("@info:tooltip", "The mask will try to close non-closed contours " "if the gap is smaller than \"Gap close hint\" value")); m_d->ui->intCleanUp->setRange(0, 100); m_d->ui->intCleanUp->setSuffix(i18n(" %")); m_d->ui->intCleanUp->setPrefix(i18n("Clean up: ")); m_d->ui->intCleanUp->setToolTip( i18nc("@info:tooltip", "The mask will try to remove parts of the key strokes " "that are placed outside the closed contours. 0% - no effect, 100% - max effect")); connect(m_d->ui->colorView, SIGNAL(sigIndexSelected(QModelIndex)), this, SLOT(entrySelected(QModelIndex))); connect(m_d->ui->btnTransparent, SIGNAL(toggled(bool)), this, SLOT(slotMakeTransparent(bool))); connect(m_d->ui->btnRemove, SIGNAL(clicked()), this, SLOT(slotRemove())); connect(m_d->ui->chkAutoUpdates, SIGNAL(toggled(bool)), m_d->ui->btnUpdate, SLOT(setDisabled(bool))); connect(m_d->ui->btnUpdate, SIGNAL(clicked()), this, SLOT(slotUpdate())); connect(m_d->ui->chkAutoUpdates, SIGNAL(toggled(bool)), this, SLOT(slotSetAutoUpdates(bool))); connect(m_d->ui->chkShowKeyStrokes, SIGNAL(toggled(bool)), this, SLOT(slotSetShowKeyStrokes(bool))); connect(m_d->ui->chkShowOutput, SIGNAL(toggled(bool)), this, SLOT(slotSetShowOutput(bool))); connect(&m_d->baseNodeChangedCompressor, SIGNAL(timeout()), this, SLOT(slotUpdateNodeProperties())); m_d->provider = provider; - m_d->colorSet.setIsGlobal(false); - m_d->colorSet.setIsEditable(true); - m_d->colorModel->setPalette(&m_d->colorSet); + m_d->colorSet->setIsGlobal(false); + m_d->colorSet->setIsEditable(true); + m_d->colorModel->setPalette(m_d->colorSet); const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8(); m_d->colorModel->addEntry(KisSwatch(KoColor(Qt::red, cs), "color1")); m_d->colorModel->addEntry(KisSwatch(KoColor(Qt::green, cs), "color2")); m_d->colorModel->addEntry(KisSwatch(KoColor(Qt::blue, cs), "color3")); } KisToolLazyBrushOptionsWidget::~KisToolLazyBrushOptionsWidget() { } void KisToolLazyBrushOptionsWidget::showEvent(QShowEvent *event) { QWidget::showEvent(event); m_d->providerSignals.addConnection( m_d->provider, SIGNAL(sigNodeChanged(KisNodeSP)), this, SLOT(slotCurrentNodeChanged(KisNodeSP))); m_d->providerSignals.addConnection( m_d->provider, SIGNAL(sigFGColorChanged(KoColor)), this, SLOT(slotCurrentFgColorChanged(KoColor))); slotCurrentNodeChanged(m_d->provider->currentNode()); slotCurrentFgColorChanged(m_d->provider->fgColor()); } void KisToolLazyBrushOptionsWidget::hideEvent(QHideEvent *event) { QWidget::hideEvent(event); m_d->providerSignals.clear(); } void KisToolLazyBrushOptionsWidget::entrySelected(QModelIndex index) { if (!index.isValid()) return; if (!qvariant_cast(index.data(KisPaletteModel::CheckSlotRole))) return; KisSwatch entry = m_d->colorModel->getEntry(index); m_d->provider->setFGColor(entry.color()); int idxInList = m_d->activeMask->keyStrokesColors().colors.indexOf(entry.color()); if (idxInList != -1) { const bool transparentChecked = idxInList == m_d->transparentColorIndex; KisSignalsBlocker b(m_d->ui->btnTransparent); m_d->ui->btnTransparent->setChecked(transparentChecked); } } void KisToolLazyBrushOptionsWidget::slotCurrentFgColorChanged(const KoColor &color) { bool found = false; QModelIndex candidateIdx = m_d->colorModel->indexForClosest(color); if (m_d->colorModel->getEntry(candidateIdx).color() == color) { found = true; } m_d->ui->btnRemove->setEnabled(found); m_d->ui->btnTransparent->setEnabled(found); if (!found) { KisSignalsBlocker b(m_d->ui->btnTransparent); m_d->ui->btnTransparent->setChecked(false); } QModelIndex newIndex = found ? candidateIdx : QModelIndex(); if (!found) { m_d->ui->colorView->selectionModel()->clear(); } if (newIndex.isValid() && newIndex != m_d->ui->colorView->currentIndex()) { m_d->ui->colorView->setCurrentIndex(newIndex); m_d->ui->colorView->update(newIndex); } } void KisToolLazyBrushOptionsWidget::slotColorLabelsChanged() { m_d->colorModel->clear(); m_d->transparentColorIndex = -1; if (m_d->activeMask) { KisColorizeMask::KeyStrokeColors colors = m_d->activeMask->keyStrokesColors(); m_d->transparentColorIndex = colors.transparentIndex; for (int i = 0; i < colors.colors.size(); i++) { const QString name = i == m_d->transparentColorIndex ? "transparent" : ""; m_d->colorModel->addEntry(KisSwatch(colors.colors[i], name)); } } slotCurrentFgColorChanged(m_d->provider->fgColor()); } void KisToolLazyBrushOptionsWidget::slotUpdateNodeProperties() { KisSignalsBlocker b1(m_d->ui->chkAutoUpdates, m_d->ui->btnUpdate, m_d->ui->chkShowKeyStrokes, m_d->ui->chkShowOutput); KisSignalsBlocker b2(m_d->ui->chkUseEdgeDetection, m_d->ui->intEdgeDetectionSize, m_d->ui->intRadius, m_d->ui->intCleanUp, m_d->ui->chkLimitToDevice); // not implemented yet! //m_d->ui->chkAutoUpdates->setEnabled(m_d->activeMask); m_d->ui->chkAutoUpdates->setEnabled(false); m_d->ui->chkAutoUpdates->setVisible(false); bool value = false; value = m_d->activeMask && KisLayerPropertiesIcons::nodeProperty(m_d->activeMask, KisLayerPropertiesIcons::colorizeNeedsUpdate, true).toBool(); m_d->ui->btnUpdate->setEnabled(m_d->activeMask && !m_d->ui->chkAutoUpdates->isChecked() && value); value = m_d->activeMask && KisLayerPropertiesIcons::nodeProperty(m_d->activeMask, KisLayerPropertiesIcons::colorizeEditKeyStrokes, true).toBool(); m_d->ui->chkShowKeyStrokes->setEnabled(m_d->activeMask); m_d->ui->chkShowKeyStrokes->setChecked(value); value = m_d->activeMask && KisLayerPropertiesIcons::nodeProperty(m_d->activeMask, KisLayerPropertiesIcons::colorizeShowColoring, true).toBool(); m_d->ui->chkShowOutput->setEnabled(m_d->activeMask); m_d->ui->chkShowOutput->setChecked(value); m_d->ui->chkUseEdgeDetection->setEnabled(m_d->activeMask); m_d->ui->chkUseEdgeDetection->setChecked(m_d->activeMask && m_d->activeMask->useEdgeDetection()); m_d->ui->intEdgeDetectionSize->setEnabled(m_d->activeMask && m_d->ui->chkUseEdgeDetection->isChecked()); m_d->ui->intEdgeDetectionSize->setValue(m_d->activeMask ? m_d->activeMask->edgeDetectionSize() : 4.0); m_d->ui->intRadius->setEnabled(m_d->activeMask); m_d->ui->intRadius->setValue(2 * (m_d->activeMask ? m_d->activeMask->fuzzyRadius() : 15)); m_d->ui->intCleanUp->setEnabled(m_d->activeMask); m_d->ui->intCleanUp->setValue(100 * (m_d->activeMask ? m_d->activeMask->cleanUpAmount() : 0.7)); m_d->ui->chkLimitToDevice->setEnabled(m_d->activeMask); m_d->ui->chkLimitToDevice->setChecked(m_d->activeMask && m_d->activeMask->limitToDeviceBounds()); } void KisToolLazyBrushOptionsWidget::slotCurrentNodeChanged(KisNodeSP node) { m_d->maskSignals.clear(); KisColorizeMask *mask = dynamic_cast(node.data()); m_d->activeMask = mask; if (m_d->activeMask) { m_d->maskSignals.addConnection( m_d->activeMask, SIGNAL(sigKeyStrokesListChanged()), this, SLOT(slotColorLabelsChanged())); m_d->maskSignals.addConnection( m_d->provider->currentImage(), SIGNAL(sigNodeChanged(KisNodeSP)), this, SLOT(slotUpdateNodeProperties())); } slotColorLabelsChanged(); slotUpdateNodeProperties(); m_d->ui->colorView->setEnabled(m_d->activeMask); } void KisToolLazyBrushOptionsWidget::slotMakeTransparent(bool value) { KIS_ASSERT_RECOVER_RETURN(m_d->activeMask); QModelIndex index = m_d->ui->colorView->currentIndex(); KisSwatch activeSwatch = m_d->colorModel->getEntry(index); if (!index.isValid()) return; int activeIndex = -1; KisColorizeMask::KeyStrokeColors colors; int i = 0; - Q_FOREACH (const QString &groupName, m_d->colorSet.getGroupNames()) { - KisSwatchGroup *group = m_d->colorSet.getGroup(groupName); + Q_FOREACH (const QString &groupName, m_d->colorSet->getGroupNames()) { + KisSwatchGroup *group = m_d->colorSet->getGroup(groupName); Q_FOREACH (const KisSwatchGroup::SwatchInfo &info, group->infoList()) { colors.colors << info.swatch.color(); if (activeSwatch == info.swatch) { activeIndex = i; } i++; } } colors.transparentIndex = value ? activeIndex : -1; m_d->activeMask->setKeyStrokesColors(colors); } void KisToolLazyBrushOptionsWidget::slotRemove() { KIS_ASSERT_RECOVER_RETURN(m_d->activeMask); QModelIndex index = m_d->ui->colorView->currentIndex(); if (!index.isValid()) return; const KoColor color = m_d->colorModel->getEntry(index).color(); m_d->activeMask->removeKeyStroke(color); } void KisToolLazyBrushOptionsWidget::slotUpdate() { KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->activeMask); KisLayerPropertiesIcons::setNodeProperty(m_d->activeMask, KisLayerPropertiesIcons::colorizeNeedsUpdate, false, m_d->provider->currentImage()); } void KisToolLazyBrushOptionsWidget::slotSetAutoUpdates(bool value) { // not implemented yet! ENTER_FUNCTION() << ppVar(value); } void KisToolLazyBrushOptionsWidget::slotSetShowKeyStrokes(bool value) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->activeMask); KisLayerPropertiesIcons::setNodeProperty(m_d->activeMask, KisLayerPropertiesIcons::colorizeEditKeyStrokes, value, m_d->provider->currentImage()); } void KisToolLazyBrushOptionsWidget::slotSetShowOutput(bool value) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->activeMask); KisLayerPropertiesIcons::setNodeProperty(m_d->activeMask, KisLayerPropertiesIcons::colorizeShowColoring, value, m_d->provider->currentImage()); } void KisToolLazyBrushOptionsWidget::slotUseEdgeDetectionChanged(bool value) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->activeMask); m_d->activeMask->setUseEdgeDetection(value); m_d->ui->intEdgeDetectionSize->setEnabled(value); } void KisToolLazyBrushOptionsWidget::slotEdgeDetectionSizeChanged(int value) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->activeMask); m_d->activeMask->setEdgeDetectionSize(value); } void KisToolLazyBrushOptionsWidget::slotRadiusChanged(int value) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->activeMask); m_d->activeMask->setFuzzyRadius(0.5 * value); } void KisToolLazyBrushOptionsWidget::slotCleanUpChanged(int value) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->activeMask); m_d->activeMask->setCleanUpAmount(qreal(value) / 100.0); } void KisToolLazyBrushOptionsWidget::slotLimitToDeviceChanged(bool value) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->activeMask); m_d->activeMask->setLimitToDeviceBounds(value); } diff --git a/sdk/tests/stroke_testing_utils.cpp b/sdk/tests/stroke_testing_utils.cpp index 7fa6ae29a6..ec3bda982a 100644 --- a/sdk/tests/stroke_testing_utils.cpp +++ b/sdk/tests/stroke_testing_utils.cpp @@ -1,369 +1,369 @@ /* * Copyright (c) 2011 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 "stroke_testing_utils.h" #include #include #include #include #include #include #include #include #include "kis_canvas_resource_provider.h" #include "kis_image.h" #include "kis_paint_device.h" #include "kis_paint_layer.h" #include "kis_group_layer.h" #include #include "testutil.h" KisImageSP utils::createImage(KisUndoStore *undoStore, const QSize &imageSize) { QRect imageRect(0,0,imageSize.width(),imageSize.height()); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(undoStore, imageRect.width(), imageRect.height(), cs, "stroke test"); KisPaintLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8); KisPaintLayerSP paintLayer2 = new KisPaintLayer(image, "paint2", OPACITY_OPAQUE_U8); KisPaintLayerSP paintLayer3 = new KisPaintLayer(image, "paint3", OPACITY_OPAQUE_U8); KisPaintLayerSP paintLayer4 = new KisPaintLayer(image, "paint4", OPACITY_OPAQUE_U8); KisPaintLayerSP paintLayer5 = new KisPaintLayer(image, "paint5", OPACITY_OPAQUE_U8); image->lock(); image->addNode(paintLayer1); image->addNode(paintLayer2); image->addNode(paintLayer3); image->addNode(paintLayer4); image->addNode(paintLayer5); image->unlock(); return image; } KoCanvasResourceProvider* utils::createResourceManager(KisImageWSP image, KisNodeSP node, const QString &presetFileName) { KoCanvasResourceProvider *manager = new KoCanvasResourceProvider(); KisViewManager::initializeResourceManager(manager); QVariant i; i.setValue(KoColor(Qt::black, image->colorSpace())); manager->setResource(KoCanvasResourceProvider::ForegroundColor, i); i.setValue(KoColor(Qt::white, image->colorSpace())); manager->setResource(KoCanvasResourceProvider::BackgroundColor, i); i.setValue(static_cast(0)); manager->setResource(KisCanvasResourceProvider::CurrentPattern, i); manager->setResource(KisCanvasResourceProvider::CurrentGradient, i); manager->setResource(KisCanvasResourceProvider::CurrentGeneratorConfiguration, i); if(!node) { node = image->root(); while(node && !dynamic_cast(node.data())) { node = node->firstChild(); } Q_ASSERT(node && dynamic_cast(node.data())); } i.setValue(node); manager->setResource(KisCanvasResourceProvider::CurrentKritaNode, i); KisPaintOpPresetSP preset; if (!presetFileName.isEmpty()) { QString fullFileName = TestUtil::fetchDataFileLazy(presetFileName); - preset = new KisPaintOpPreset(fullFileName); + preset = KisPaintOpPresetSP(new KisPaintOpPreset(fullFileName)); bool presetValid = preset->load(); Q_ASSERT(presetValid); Q_UNUSED(presetValid); i.setValue(preset); manager->setResource(KisCanvasResourceProvider::CurrentPaintOpPreset, i); } i.setValue(COMPOSITE_OVER); manager->setResource(KisCanvasResourceProvider::CurrentCompositeOp, i); i.setValue(false); manager->setResource(KisCanvasResourceProvider::MirrorHorizontal, i); i.setValue(false); manager->setResource(KisCanvasResourceProvider::MirrorVertical, i); i.setValue(1.0); manager->setResource(KisCanvasResourceProvider::Opacity, i); i.setValue(1.0); manager->setResource(KisCanvasResourceProvider::HdrExposure, i); return manager; } utils::StrokeTester::StrokeTester(const QString &name, const QSize &imageSize, const QString &presetFilename) : m_name(name), m_imageSize(imageSize), m_presetFilename(presetFilename), m_numIterations(1), m_baseFuzziness(1) { } utils::StrokeTester::~StrokeTester() { } void utils::StrokeTester::setNumIterations(int value) { m_numIterations = value; } void utils::StrokeTester::setBaseFuzziness(int value) { m_baseFuzziness = value; } void utils::StrokeTester::testSimpleStroke() { testOneStroke(false, true, false, true); } int utils::StrokeTester::lastStrokeTime() const { return m_strokeTime; } void utils::StrokeTester::test() { testOneStroke(false, false, false); testOneStroke(false, true, false); testOneStroke(true, false, false); testOneStroke(true, true, false); // The same but with updates (compare against projection) testOneStroke(false, false, false, true); testOneStroke(false, true, false, true); testOneStroke(true, false, false, true); testOneStroke(true, true, false, true); // The same, but with an external layer testOneStroke(false, false, true); testOneStroke(false, true, true); testOneStroke(true, false, true); testOneStroke(true, true, true); } void utils::StrokeTester::benchmark() { // not cancelled, indirect painting, internal, no updates, no qimage doStroke(false, false, false, false); } void utils::StrokeTester::testSimpleStrokeNoVerification() { doStroke(false, false, true, false); } void utils::StrokeTester::testOneStroke(bool cancelled, bool indirectPainting, bool externalLayer, bool testUpdates) { // TODO: indirectPainting option is not used anymore! The real value is // taken from the preset! QString testName = formatTestName(m_name, cancelled, indirectPainting, externalLayer); dbgKrita << "Testcase:" << testName << "(compare against " << (testUpdates ? "projection" : "layer") << ")"; QImage resultImage; resultImage = doStroke(cancelled, externalLayer, testUpdates); QImage refImage; refImage.load(referenceFile(testName)); QPoint temp; if(!TestUtil::compareQImages(temp, refImage, resultImage, m_baseFuzziness, m_baseFuzziness)) { refImage.save(dumpReferenceFile(testName)); resultImage.save(resultFile(testName)); QFAIL("Images do not coincide"); } } QString utils::StrokeTester::formatTestName(const QString &baseName, bool cancelled, bool indirectPainting, bool externalLayer) { QString result = baseName; result += "_" + m_presetFilename; result += indirectPainting ? "_indirect" : "_incremental"; result += cancelled ? "_cancelled" : "_finished"; result += externalLayer ? "_external" : "_internal"; return result; } QString utils::StrokeTester::referenceFile(const QString &testName) { QString path = QString(FILES_DATA_DIR) + QDir::separator() + m_name + QDir::separator(); path += testName; path += ".png"; return path; } QString utils::StrokeTester::dumpReferenceFile(const QString &testName) { QString path = QString(FILES_OUTPUT_DIR) + QDir::separator(); path += testName; path += "_expected"; path += ".png"; return path; } QString utils::StrokeTester::resultFile(const QString &testName) { QString path = QString(FILES_OUTPUT_DIR) + QDir::separator(); path += testName; path += ".png"; return path; } QImage utils::StrokeTester::doStroke(bool cancelled, bool externalLayer, bool testUpdates, bool needQImage) { KisImageSP image = utils::createImage(0, m_imageSize); KoCanvasResourceProvider *manager = utils::createResourceManager(image, 0, m_presetFilename); KisNodeSP currentNode; for (int i = 0; i < m_numIterations; i++) { modifyResourceManager(manager, image, i); KisResourcesSnapshotSP resources = new KisResourcesSnapshot(image, image->rootLayer()->firstChild(), manager); if(externalLayer) { KisNodeSP externalNode = new KisPaintLayer(0, "extlyr", OPACITY_OPAQUE_U8, image->colorSpace()); resources->setCurrentNode(externalNode); Q_ASSERT(resources->currentNode() == externalNode); } initImage(image, resources->currentNode(), i); QElapsedTimer strokeTime; strokeTime.start(); KisStrokeStrategy *stroke = createStroke(resources, image); m_strokeId = image->startStroke(stroke); addPaintingJobs(image, resources, i); if(!cancelled) { image->endStroke(m_strokeId); } else { image->cancelStroke(m_strokeId); } image->waitForDone(); m_strokeTime = strokeTime.elapsed(); currentNode = resources->currentNode(); } beforeCheckingResult(image, currentNode); QImage resultImage; if(needQImage) { KisPaintDeviceSP device = testUpdates ? image->projection() : currentNode->paintDevice(); resultImage = device->convertToQImage(0, 0, 0, image->width(), image->height()); } image = 0; delete manager; return resultImage; } void utils::StrokeTester::modifyResourceManager(KoCanvasResourceProvider *manager, KisImageWSP image, int iteration) { Q_UNUSED(iteration); modifyResourceManager(manager, image); } void utils::StrokeTester::modifyResourceManager(KoCanvasResourceProvider *manager, KisImageWSP image) { Q_UNUSED(manager); Q_UNUSED(image); } void utils::StrokeTester::initImage(KisImageWSP image, KisNodeSP activeNode, int iteration) { Q_UNUSED(iteration); initImage(image, activeNode); } void utils::StrokeTester::initImage(KisImageWSP image, KisNodeSP activeNode) { Q_UNUSED(image); Q_UNUSED(activeNode); } void utils::StrokeTester::addPaintingJobs(KisImageWSP image, KisResourcesSnapshotSP resources, int iteration) { Q_UNUSED(iteration); addPaintingJobs(image, resources); } void utils::StrokeTester::addPaintingJobs(KisImageWSP image, KisResourcesSnapshotSP resources) { Q_UNUSED(image); Q_UNUSED(resources); } void utils::StrokeTester::beforeCheckingResult(KisImageWSP image, KisNodeSP activeNode) { Q_UNUSED(image); Q_UNUSED(activeNode); } diff --git a/sdk/tests/ui_manager_test.h b/sdk/tests/ui_manager_test.h index 76117f71de..3d5df6c214 100644 --- a/sdk/tests/ui_manager_test.h +++ b/sdk/tests/ui_manager_test.h @@ -1,180 +1,180 @@ /* * Copyright (c) 2012 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. */ #ifndef __UI_MANAGER_TEST_H #define __UI_MANAGER_TEST_H #include "testutil.h" #include "qimage_based_test.h" #include "ksharedconfig.h" #include #include #include "KisResourceServerProvider.h" #include "kis_canvas_resource_provider.h" #include "kis_filter_strategy.h" #include "kis_selection_manager.h" #include "kis_node_manager.h" #include "KisViewManager.h" #include "KisView.h" #include "KisPart.h" #include #include #include "KisMainWindow.h" #include "kis_selection_mask.h" namespace TestUtil { class UiManagerTest : public TestUtil::QImageBasedTest { public: UiManagerTest(bool useSelection, bool useShapeLayer, const QString &testName) : QImageBasedTest(testName) // "selection_manager_test" { undoStore = new KisSurrogateUndoStore(); image = createImage(undoStore); part = KisPart::instance(); doc = qobject_cast(part->createDocument()); doc->setCurrentImage(image); if(useSelection) addGlobalSelection(image); if(useShapeLayer) addShapeLayer(doc, image); image->initialRefreshGraph(); mainWindow = new KisMainWindow(); imageView = new KisView(doc, mainWindow->resourceManager(), mainWindow->actionCollection(), mainWindow); view = new KisViewManager(mainWindow, mainWindow->actionCollection()); - KoPattern *newPattern = new KoPattern(fetchDataFileLazy("HR_SketchPaper_01.pat")); + KoPatternSP newPattern(new KoPattern(fetchDataFileLazy("HR_SketchPaper_01.pat"))); newPattern->load(); Q_ASSERT(newPattern->valid()); view->resourceProvider()->slotPatternActivated(newPattern); KoColor fgColor(Qt::black, image->colorSpace()); KoColor bgColor(Qt::white, image->colorSpace()); view->resourceProvider()->blockSignals(true); view->resourceProvider()->setBGColor(bgColor); view->resourceProvider()->setFGColor(fgColor); view->resourceProvider()->setOpacity(1.0); KisNodeSP paint1 = findNode(image->root(), "paint1"); Q_ASSERT(paint1); imageView->setViewManager(view); view->setCurrentView(imageView); view->nodeManager()->slotUiActivatedNode(paint1); selectionManager = view->selectionManager(); Q_ASSERT(selectionManager); actionManager = view->actionManager(); Q_ASSERT(actionManager); QVERIFY(checkLayersInitial()); } ~UiManagerTest() { /** * Here is a weird way of precessing pending events. * This is needed for the dummies facade could process * all the queued events telling it some nodes were * added/deleted */ QApplication::processEvents(); QTest::qSleep(500); QApplication::processEvents(); delete mainWindow; delete doc; /** * The event queue may have up to 200k events * by the time all the tests are finished. Removing * all of them may last forever, so clear them after * every single test is finished */ QApplication::removePostedEvents(0); } void checkUndo() { undoStore->undo(); image->waitForDone(); QVERIFY(checkLayersInitial()); } void checkDoubleUndo() { undoStore->undo(); undoStore->undo(); image->waitForDone(); QVERIFY(checkLayersInitial()); } void startConcurrentTask() { KisFilterStrategy * filter = new KisBoxFilterStrategy(); QSize initialSize = image->size(); image->scaleImage(2 * initialSize, image->xRes(), image->yRes(), filter); image->waitForDone(); image->scaleImage(initialSize, image->xRes(), image->yRes(), filter); } using QImageBasedTest::checkLayers; bool checkLayers(const QString &name) { return checkLayers(image, name); } using QImageBasedTest::checkLayersInitial; bool checkLayersInitial() { return checkLayersInitial(image); } bool checkLayersFuzzy(const QString &name) { return checkLayers(image, name, 1); } bool checkSelectionOnly(const QString &name) { KisNodeSP mask = dynamic_cast(image->root().data())->selectionMask(); return checkOneLayer(image, mask, name); } bool checkNoSelection() { KisNodeSP mask = dynamic_cast(image->root().data())->selectionMask(); return !mask && !image->globalSelection(); } KisImageSP image; KisSelectionManager *selectionManager; KisActionManager *actionManager; KisSurrogateUndoStore *undoStore; protected: KisView *imageView; KisViewManager *view; KisDocument *doc; KisPart *part; KisMainWindow *mainWindow; }; } #endif /* __UI_MANAGER_TEST_H */