diff --git a/3rdparty/ext_gmic/CMakeLists.txt b/3rdparty/ext_gmic/CMakeLists.txt index c97d6e9080..0ceb0b85d9 100644 --- a/3rdparty/ext_gmic/CMakeLists.txt +++ b/3rdparty/ext_gmic/CMakeLists.txt @@ -1,41 +1,41 @@ SET(PREFIX_ext_gmic "${EXTPREFIX}" ) # Download the gmic sources ExternalProject_Add( ext_gmic_base DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} - URL https://gmic.eu/files/source/gmic_2.5.6.tar.gz - URL_MD5 8deabebc29081657986ae6531e3fc1d7 + URL https://gmic.eu/files/source/gmic_2.6.7.tar.gz + URL_MD5 1d55ec5d349ccf0ef78cf8d1b4a42af8 PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/cmake.diff COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/no_threads.diff SOURCE_DIR gmic CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${PREFIX_ext_gmic} -D -DCMAKE_BUILD_TYPE=Release ${GLOBAL_PROFILE} BUILD_COMMAND "" INSTALL_COMMAND "" BUILD_IN_SOURCE 1 ) # Download and build gmic-qt # FIXME: Forcing CMAKE_BUILD_TYPE to Release ExternalProject_Add( ext_gmic_qt DOWNLOAD_DIR ${EXTERNALS_DOWNLOAD_DIR} - URL https://github.com/c-koi/gmic-qt/archive/v.2.5.6.tar.gz - URL_MD5 4e7cf71d6348d44f98d3c132433c358c + URL https://github.com/c-koi/gmic-qt/archive/v.2.6.7.tar.gz + URL_MD5 bdbd6e77d78e478e8653c1396065afc5 PATCH_COMMAND ${PATCH_COMMAND} -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/desktop_icon.diff SOURCE_DIR gmic-qt INSTALL_DIR ${PREFIX_ext_gmic} CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${PREFIX_ext_gmic} -DGMIC_QT_HOST=krita -DCMAKE_BUILD_TYPE=Release ${GLOBAL_PROFILE} UPDATE_COMMAND "" DEPENDS ext_gmic_base ) add_custom_target(ext_gmic) add_dependencies(ext_gmic ext_gmic_qt) diff --git a/krita/data/aboutdata/developers.txt b/krita/data/aboutdata/developers.txt index 69f73890f5..75961c6bd1 100644 --- a/krita/data/aboutdata/developers.txt +++ b/krita/data/aboutdata/developers.txt @@ -1,201 +1,202 @@ Boudewijn Rempt Aaron J. Seigo Adam Celarek Adam Pigg Adriaan de Groot Adrian Page Adrian Schroeter Albert Astals Cid Alberto Villa Alexander Neundorf Alexander Potashev Alexis Ménard Alfredo Beaumont Sainz Allen Winter Ana Beatriz Guerrero López Andras Mantia Andreas Hartmetz Andreas Lundin André Marcelo Alvarenga Andrew Coles Andre Woebbeking Andrius da Costa Ribas Andy Fawcett Anne-Marie Mahfouf Ariya Hidayat Arjen Hiemstra Bart Coppens Ben Cooksley Benjamin K. Stuhl Benjamin Meyer Benjamin Reed Benoît Jacob Ben Schleimer Bernhard Rosenkraenzer Bo Thorsen Brad Hards Bram Schoenmakers Burkhard Lück Carlo Segato C. Boemann Christer Stenbrenden Christian Ehrlicher Christian Mueller Christoph Feck Chusslove Illich Clarence Dang Cyrille Berger Daniel M. Duley Daniel Molkentin Dan Leinir Turthra Jensen Dan Meltzer Danny Allen David Faure David Gowers Dirk Mueller Dirk Schönberger Dmitry Kazakov Edward Apap Elvis Stansvik Emanuele Tamponi Emmet O'Neill Enrique Matías Sánchez Eoin O'Neill Fabian Kosmale Frank Osterfeld Frederik Schwarzer Fredrik Edemar Fredy Yanardi Friedrich W. H. Kossebau Gábor Lehel Gary Cramblitt Geoffry Song Gioele Barabucci Giovanni Venturi Gopalakrishna Bhat A Hanna Scott Harald Sitter Hasso Tepper Helge Deller Helio Castro Hideki Saito Hoàng Đức Hiếu Hugo Pereira Da Costa Inge Wallin Ingo Klöcker İsmail Dönmez Ivan Yossi Jaime Jaime Torres Jaison Lee Jakob Petsovits Jakub Stachowski Jan Hambrecht Jarosław Staniek Jens Herden Jessica Hall Johannes Simon John Layt Jonathan Riddell Jonathan Singer José Luis Vergara Juan Luis Boya García Juan Palacios Jure Repinc Kai-Uwe Behrmann +Karl Ove Hufthammer Kevin Krammer Kevin Ottens Kurt Pfeifle Laurent Montel Lauri Watts Leo Savernik Lukáš Tinkl Lukáš Tvrdý Maciej Mrozowski Malcolm Hunter Manuel Riecke manu tortosa Marc Pegon Marijn Kruisselbrink Martin Ellis Martin Gräßlin Matthew Woehlke Matthias Klumpp Matthias Kretz Matus Talcik Maximiliano Curia Melchior Franz Michael David Howell Michael Drueing Michael Thaler Michel Hermier Mohit Goyal Mojtaba Shahi Senobari Montel Laurent Moritz Molch Nick Shaforostoff Nicolas Goutte Olivier Goffart Patrick Julien Patrick Spendrin Pavel Belskiy Pavel Heimlich Peter Simonsson Pierre Ducroquet Pierre Stirnweiss Pino Toscano Rafael Fernández López Raphael Langerhorst Rex Dieter Rob Buis Roopesh Chander Sahil Nagpal Salil Kapur Samuel Buttigieg Sander Koning Sascha Suelzer Scott Petrovic Scott Wheeler Sebastian Sauer Shivaraman Aiyer Siddharth Sharma Silvio Heinrich Somsubhra Bairi Spencer Brown Srikanth Tiyyagura Stefan Nikolaus Stephan Binner Stephan Kulow Stuart Dickson Sune Vuorela Sven Langkamp Thiago Macieira Thomas Capricelli Thomas Friedrichsmeier Thomas Klausner Thomas Nagy Thomas Zander Thorsten Staerk Thorsten Zachmann Tim Beaulen Timothée Giet Tobias Koenig Tom Burdick Torio Mlshi Torsten Rahn Unai Garro Urs Wolfer Vadim Zhukov Vera Lukman Victor Lafon Victor Wåhlström Volker Krause Waldo Bastian Werner Trobin Wilco Greven Will Entriken William Steidtmann Wolthera van Hovell Yann Bodson Yue Liu Yuri Chornoivan diff --git a/libs/image/commands_new/kis_saved_commands.cpp b/libs/image/commands_new/kis_saved_commands.cpp index ddec094bd9..b6e04b57a5 100644 --- a/libs/image/commands_new/kis_saved_commands.cpp +++ b/libs/image/commands_new/kis_saved_commands.cpp @@ -1,305 +1,317 @@ /* * 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_saved_commands.h" #include #include "kis_image_interfaces.h" #include "kis_stroke_strategy_undo_command_based.h" KisSavedCommandBase::KisSavedCommandBase(const KUndo2MagicString &name, KisStrokesFacade *strokesFacade) : KUndo2Command(name), m_strokesFacade(strokesFacade), m_skipOneRedo(true) { } KisSavedCommandBase::~KisSavedCommandBase() { } KisStrokesFacade* KisSavedCommandBase::strokesFacade() { return m_strokesFacade; } void KisSavedCommandBase::runStroke(bool undo) { KisStrokeStrategyUndoCommandBased *strategy = new KisStrokeStrategyUndoCommandBased(text(), undo, 0); strategy->setUsedWhileUndoRedo(true); KisStrokeId id = m_strokesFacade->startStroke(strategy); addCommands(id, undo); m_strokesFacade->endStroke(id); } void KisSavedCommandBase::undo() { runStroke(true); } void KisSavedCommandBase::redo() { /** * All the commands are first executed in the stroke and then * added to the undo stack. It means that the first redo should be * skipped */ if(m_skipOneRedo) { m_skipOneRedo = false; return; } runStroke(false); } KisSavedCommand::KisSavedCommand(KUndo2CommandSP command, KisStrokesFacade *strokesFacade) : KisSavedCommandBase(command->text(), strokesFacade), m_command(command) { } int KisSavedCommand::id() const { return m_command->id(); } bool KisSavedCommand::mergeWith(const KUndo2Command* command) { const KisSavedCommand *other = dynamic_cast(command); if (other) { command = other->m_command.data(); } return m_command->mergeWith(command); } void KisSavedCommand::addCommands(KisStrokeId id, bool undo) { strokesFacade()-> addJob(id, new KisStrokeStrategyUndoCommandBased::Data(m_command, undo)); } int KisSavedCommand::timedId() { return m_command->timedId(); } void KisSavedCommand::setTimedID(int timedID) { m_command->setTimedID(timedID); } bool KisSavedCommand::timedMergeWith(KUndo2Command *other) { return m_command->timedMergeWith(other); } QVector KisSavedCommand::mergeCommandsVector() { return m_command->mergeCommandsVector(); } void KisSavedCommand::setTime() { m_command->setTime(); } QTime KisSavedCommand::time() { return m_command->time(); } void KisSavedCommand::setEndTime() { m_command->setEndTime(); } QTime KisSavedCommand::endTime() { return m_command->endTime(); } bool KisSavedCommand::isMerged() { return m_command->isMerged(); } struct KisSavedMacroCommand::Private { struct SavedCommand { KUndo2CommandSP command; KisStrokeJobData::Sequentiality sequentiality; KisStrokeJobData::Exclusivity exclusivity; }; QVector commands; int macroId = -1; const KisSavedMacroCommand *overriddenCommand = 0; QVector skipWhenOverride; }; KisSavedMacroCommand::KisSavedMacroCommand(const KUndo2MagicString &name, KisStrokesFacade *strokesFacade) : KisSavedCommandBase(name, strokesFacade), m_d(new Private()) { } KisSavedMacroCommand::~KisSavedMacroCommand() { delete m_d; } void KisSavedMacroCommand::setMacroId(int value) { m_d->macroId = value; } int KisSavedMacroCommand::id() const { return m_d->macroId; } bool KisSavedMacroCommand::mergeWith(const KUndo2Command* command) { const KisSavedMacroCommand *other = dynamic_cast(command); - if (!other || other->id() != id()) return false; + if (!other || other->id() != id() || id() < 0 || other->id() < 0) return false; QVector &otherCommands = other->m_d->commands; if (other->m_d->overriddenCommand == this) { m_d->commands.clear(); Q_FOREACH (Private::SavedCommand cmd, other->m_d->commands) { if (!other->m_d->skipWhenOverride.contains(cmd.command.data())) { m_d->commands.append(cmd); } } - setExtraData(other->extraData()->clone()); + if (other->extraData()) { + setExtraData(other->extraData()->clone()); + } else { + setExtraData(0); + } return true; } if (m_d->commands.size() != otherCommands.size()) return false; auto it = m_d->commands.constBegin(); auto end = m_d->commands.constEnd(); auto otherIt = otherCommands.constBegin(); auto otherEnd = otherCommands.constEnd(); bool sameCommands = true; while (it != end && otherIt != otherEnd) { - if (it->command->id() != otherIt->command->id() || + if (it->command->id() < 0 || + otherIt->command->id() < 0 || + it->command->id() != otherIt->command->id() || it->sequentiality != otherIt->sequentiality || it->exclusivity != otherIt->exclusivity) { sameCommands = false; break; } ++it; ++otherIt; } if (!sameCommands) return false; it = m_d->commands.constBegin(); otherIt = otherCommands.constBegin(); while (it != end && otherIt != otherEnd) { if (it->command->id() != -1) { bool result = it->command->mergeWith(otherIt->command.data()); KIS_ASSERT_RECOVER(result) { return false; } } ++it; ++otherIt; } + if (other->extraData()) { + setExtraData(other->extraData()->clone()); + } else { + setExtraData(0); + } + return true; } void KisSavedMacroCommand::addCommand(KUndo2CommandSP command, KisStrokeJobData::Sequentiality sequentiality, KisStrokeJobData::Exclusivity exclusivity) { Private::SavedCommand item; item.command = command; item.sequentiality = sequentiality; item.exclusivity = exclusivity; m_d->commands.append(item); } void KisSavedMacroCommand::performCancel(KisStrokeId id, bool strokeUndo) { addCommands(id, !strokeUndo); } void KisSavedMacroCommand::getCommandExecutionJobs(QVector *jobs, bool undo) const { QVector::iterator it; if(!undo) { for(it = m_d->commands.begin(); it != m_d->commands.end(); it++) { *jobs << new KisStrokeStrategyUndoCommandBased:: Data(it->command, undo, it->sequentiality, it->exclusivity); } } else { for(it = m_d->commands.end(); it != m_d->commands.begin();) { --it; *jobs << new KisStrokeStrategyUndoCommandBased:: Data(it->command, undo, it->sequentiality, it->exclusivity); } } } void KisSavedMacroCommand::setOverrideInfo(const KisSavedMacroCommand *overriddenCommand, const QVector &skipWhileOverride) { m_d->overriddenCommand = overriddenCommand; m_d->skipWhenOverride = skipWhileOverride; } void KisSavedMacroCommand::addCommands(KisStrokeId id, bool undo) { QVector jobs; getCommandExecutionJobs(&jobs, undo); Q_FOREACH (KisStrokeJobData *job, jobs) { strokesFacade()->addJob(id, job); } } diff --git a/libs/ui/KisResourceBundle.cpp b/libs/ui/KisResourceBundle.cpp index af333a20d3..13e25f58b9 100644 --- a/libs/ui/KisResourceBundle.cpp +++ b/libs/ui/KisResourceBundle.cpp @@ -1,649 +1,649 @@ /* * 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).completeBaseName()); 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(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")); + addMeta("updated", QDateTime::currentDateTime().toString(Qt::ISODate)); 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 == ResourceType::Gradients) { KoResourceServer* gradientServer = KoResourceServerProvider::instance()->gradientServer(); Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { KoResourceSP res = gradientServer->resourceByMD5(ref.md5sum); if (!res) res = gradientServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName()); if (!saveResourceToStore(res, store.data(), ResourceType::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 == ResourceType::Patterns) { KoResourceServer* patternServer = KoResourceServerProvider::instance()->patternServer(); Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { KoResourceSP res = patternServer->resourceByMD5(ref.md5sum); if (!res) res = patternServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName()); if (!saveResourceToStore(res, store.data(), ResourceType::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 == ResourceType::Brushes) { KoResourceServer* brushServer = KisBrushServerProvider::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()); KoResourceSP res = brush; if (!saveResourceToStore(res, store.data(), ResourceType::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 == ResourceType::Palettes) { KoResourceServer* paletteServer = KoResourceServerProvider::instance()->paletteServer(); Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { KoResourceSP res = paletteServer->resourceByMD5(ref.md5sum); if (!res) res = paletteServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName()); if (!saveResourceToStore(res, store.data(), ResourceType::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 == ResourceType::Workspaces) { KoResourceServer< KisWorkspaceResource >* workspaceServer = KisResourceServerProvider::instance()->workspaceServer(); Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { KoResourceSP res = workspaceServer->resourceByMD5(ref.md5sum); if (!res) res = workspaceServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName()); if (!saveResourceToStore(res, store.data(), ResourceType::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 == ResourceType::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, store.data(), ResourceType::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 == ResourceType::GamutMasks) { KoResourceServer* gamutMaskServer = KoResourceServerProvider::instance()->gamutMaskServer(); Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, m_manifest.files(resType)) { KoResourceSP res = gamutMaskServer->resourceByMD5(ref.md5sum); if (!res) res = gamutMaskServer->resourceByFilename(QFileInfo(ref.resourcePath).fileName()); if (!saveResourceToStore(res, store.data(), ResourceType::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; } 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); } QStringList KisResourceBundle::resourceTypes() const { return m_manifest.types(); } QList KisResourceBundle::resources(const QString &resType) const { QList references = m_manifest.files(resType); QList ret; Q_FOREACH (const KisResourceBundleManifest::ResourceReference &ref, references) { if (resType == ResourceType::Gradients) { KoResourceServer* gradientServer = KoResourceServerProvider::instance()->gradientServer(); KoResourceSP res = gradientServer->resourceByMD5(ref.md5sum); if (res) ret << res; } else if (resType == ResourceType::Patterns) { KoResourceServer* patternServer = KoResourceServerProvider::instance()->patternServer(); KoResourceSP res = patternServer->resourceByMD5(ref.md5sum); if (res) ret << res; } else if (resType == ResourceType::Brushes) { KoResourceServer *brushServer = KisBrushServerProvider::instance()->brushServer(); KoResourceSP res = brushServer->resourceByMD5(ref.md5sum); if (res) ret << res; } else if (resType == ResourceType::Palettes) { KoResourceServer* paletteServer = KoResourceServerProvider::instance()->paletteServer(); KoResourceSP res = paletteServer->resourceByMD5(ref.md5sum); if (res) ret << res; } else if (resType == ResourceType::Workspaces) { KoResourceServer< KisWorkspaceResource >* workspaceServer = KisResourceServerProvider::instance()->workspaceServer(); KoResourceSP res = workspaceServer->resourceByMD5(ref.md5sum); if (res) ret << res; } else if (resType == ResourceType::PaintOpPresets) { KisPaintOpPresetResourceServer* paintoppresetServer = KisResourceServerProvider::instance()->paintOpPresetServer(); KisPaintOpPresetSP res = paintoppresetServer->resourceByMD5(ref.md5sum); if (res) ret << res; } else if (resType == ResourceType::GamutMasks) { KoResourceServer* gamutMaskServer = KoResourceServerProvider::instance()->gamutMaskServer(); 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::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")); + addMeta("updated", QDateTime::currentDateTime().toString(Qt::ISODate)); 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/KisWelcomePageWidget.cpp b/libs/ui/KisWelcomePageWidget.cpp index 9bba1b17ce..f1edb64594 100644 --- a/libs/ui/KisWelcomePageWidget.cpp +++ b/libs/ui/KisWelcomePageWidget.cpp @@ -1,341 +1,359 @@ /* This file is part of the KDE project * Copyright (C) 2018 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 "KisWelcomePageWidget.h" #include #include #include #include +#include +#include #include "kis_action_manager.h" #include "kactioncollection.h" #include "kis_action.h" #include "KConfigGroup" #include "KSharedConfig" #include #include #include "kis_icon_utils.h" #include "krita_utils.h" #include "KoStore.h" #include "kis_config.h" +#include "KisDocument.h" +#include +#include +#include KisWelcomePageWidget::KisWelcomePageWidget(QWidget *parent) : QWidget(parent) { setupUi(this); recentDocumentsListView->setDragEnabled(false); recentDocumentsListView->viewport()->setAutoFillBackground(false); recentDocumentsListView->setSpacing(2); // set up URLs that go to web browser manualLink->setTextFormat(Qt::RichText); manualLink->setTextInteractionFlags(Qt::TextBrowserInteraction); manualLink->setOpenExternalLinks(true); gettingStartedLink->setTextFormat(Qt::RichText); gettingStartedLink->setTextInteractionFlags(Qt::TextBrowserInteraction); gettingStartedLink->setOpenExternalLinks(true); supportKritaLink->setTextFormat(Qt::RichText); supportKritaLink->setTextInteractionFlags(Qt::TextBrowserInteraction); supportKritaLink->setOpenExternalLinks(true); userCommunityLink->setTextFormat(Qt::RichText); userCommunityLink->setTextInteractionFlags(Qt::TextBrowserInteraction); userCommunityLink->setOpenExternalLinks(true); kritaWebsiteLink->setTextFormat(Qt::RichText); kritaWebsiteLink->setTextInteractionFlags(Qt::TextBrowserInteraction); kritaWebsiteLink->setOpenExternalLinks(true); sourceCodeLink->setTextFormat(Qt::RichText); sourceCodeLink->setTextInteractionFlags(Qt::TextBrowserInteraction); sourceCodeLink->setOpenExternalLinks(true); poweredByKDELink->setTextFormat(Qt::RichText); poweredByKDELink->setTextInteractionFlags(Qt::TextBrowserInteraction); poweredByKDELink->setOpenExternalLinks(true); kdeIcon->setIconSize(QSize(20, 20)); kdeIcon->setIcon(KisIconUtils::loadIcon(QStringLiteral("kde")).pixmap(20)); connect(chkShowNews, SIGNAL(toggled(bool)), newsWidget, SLOT(toggleNews(bool))); // configure the News area KisConfig cfg(true); bool m_getNews = cfg.readEntry("FetchNews", false); chkShowNews->setChecked(m_getNews); setAcceptDrops(true); } KisWelcomePageWidget::~KisWelcomePageWidget() { } void KisWelcomePageWidget::setMainWindow(KisMainWindow* mainWin) { if (mainWin) { m_mainWindow = mainWin; // set the shortcut links from actions (only if a shortcut exists) if ( mainWin->viewManager()->actionManager()->actionByName("file_new")->shortcut().toString() != "") { newFileLinkShortcut->setText(QString("(") + mainWin->viewManager()->actionManager()->actionByName("file_new")->shortcut().toString() + QString(")")); } if (mainWin->viewManager()->actionManager()->actionByName("file_open")->shortcut().toString() != "") { openFileShortcut->setText(QString("(") + mainWin->viewManager()->actionManager()->actionByName("file_open")->shortcut().toString() + QString(")")); } connect(recentDocumentsListView, SIGNAL(clicked(QModelIndex)), this, SLOT(recentDocumentClicked(QModelIndex))); // we need the view manager to actually call actions, so don't create the connections // until after the view manager is set connect(newFileLink, SIGNAL(clicked(bool)), this, SLOT(slotNewFileClicked())); connect(openFileLink, SIGNAL(clicked(bool)), this, SLOT(slotOpenFileClicked())); connect(clearRecentFilesLink, SIGNAL(clicked(bool)), this, SLOT(slotClearRecentFiles())); slotUpdateThemeColors(); } } void KisWelcomePageWidget::showDropAreaIndicator(bool show) { if (!show) { QString dropFrameStyle = "QFrame#dropAreaIndicator { border: 0px }"; dropFrameBorder->setStyleSheet(dropFrameStyle); } else { QColor textColor = qApp->palette().color(QPalette::Text); QColor backgroundColor = qApp->palette().color(QPalette::Background); QColor blendedColor = KritaUtils::blendColors(textColor, backgroundColor, 0.8); // QColor.name() turns it into a hex/web format QString dropFrameStyle = QString("QFrame#dropAreaIndicator { border: 2px dotted ").append(blendedColor.name()).append(" }") ; dropFrameBorder->setStyleSheet(dropFrameStyle); } } void KisWelcomePageWidget::slotUpdateThemeColors() { QColor textColor = qApp->palette().color(QPalette::Text); QColor backgroundColor = qApp->palette().color(QPalette::Background); // make the welcome screen labels a subtle color so it doesn't clash with the main UI elements QColor blendedColor = KritaUtils::blendColors(textColor, backgroundColor, 0.8); QString blendedStyle = QString("color: ").append(blendedColor.name()); // what labels to change the color... startTitleLabel->setStyleSheet(blendedStyle); recentDocumentsLabel->setStyleSheet(blendedStyle); helpTitleLabel->setStyleSheet(blendedStyle); newFileLinkShortcut->setStyleSheet(blendedStyle); openFileShortcut->setStyleSheet(blendedStyle); clearRecentFilesLink->setStyleSheet(blendedStyle); recentDocumentsListView->setStyleSheet(blendedStyle); newFileLink->setStyleSheet(blendedStyle); openFileLink->setStyleSheet(blendedStyle); // giving the drag area messaging a dotted border QString dottedBorderStyle = QString("border: 2px dotted ").append(blendedColor.name()).append("; color:").append(blendedColor.name()).append( ";"); dragImageHereLabel->setStyleSheet(dottedBorderStyle); // make drop area QFrame have a dotted line dropFrameBorder->setObjectName("dropAreaIndicator"); QString dropFrameStyle = QString("QFrame#dropAreaIndicator { border: 4px dotted ").append(blendedColor.name()).append("}"); dropFrameBorder->setStyleSheet(dropFrameStyle); // only show drop area when we have a document over the empty area showDropAreaIndicator(false); // add icons for new and open settings to make them stand out a bit more openFileLink->setIconSize(QSize(30, 30)); newFileLink->setIconSize(QSize(30, 30)); openFileLink->setIcon(KisIconUtils::loadIcon("document-open")); newFileLink->setIcon(KisIconUtils::loadIcon("document-new")); kdeIcon->setIcon(KisIconUtils::loadIcon(QStringLiteral("kde")).pixmap(20)); // HTML links seem to be a bit more stubborn with theme changes... setting inline styles to help with color change userCommunityLink->setText(QString("").append(i18n("User Community")).append("")); gettingStartedLink->setText(QString("").append(i18n("Getting Started")).append("")); manualLink->setText(QString("").append(i18n("User Manual")).append("")); supportKritaLink->setText(QString("").append(i18n("Support Krita")).append("")); kritaWebsiteLink->setText(QString("").append(i18n("Krita Website")).append("")); sourceCodeLink->setText(QString("").append(i18n("Source Code")).append("")); poweredByKDELink->setText(QString("").append(i18n("Powered by KDE")).append("")); // re-populate recent files since they might have themed icons populateRecentDocuments(); } void KisWelcomePageWidget::populateRecentDocuments() { m_recentFilesModel.clear(); // clear existing data before it gets re-populated // grab recent files data int numRecentFiles = m_mainWindow->recentFilesUrls().length() > 5 ? 5 : m_mainWindow->recentFilesUrls().length(); // grab at most 5 for (int i = 0; i < numRecentFiles; i++ ) { QStandardItem *recentItem = new QStandardItem(1,2); // 1 row, 1 column recentItem->setIcon(KisIconUtils::loadIcon("document-export")); QString recentFileUrlPath = m_mainWindow->recentFilesUrls().at(i).toLocalFile(); QString fileName = recentFileUrlPath.split("/").last(); if (m_thumbnailMap.contains(recentFileUrlPath)) { recentItem->setIcon(m_thumbnailMap[recentFileUrlPath]); } else { - if (QFileInfo(recentFileUrlPath).exists()) { - if (recentFileUrlPath.toLower().endsWith("ora") || recentFileUrlPath.toLower().endsWith("kra")) { + QFileInfo fi(recentFileUrlPath); + + if (fi.exists()) { + if (fi.suffix() == "ora" || fi.suffix() == "kra") { QScopedPointer store(KoStore::createStore(recentFileUrlPath, KoStore::Read)); if (store) { QString thumbnailpath; if (store->hasFile(QString("Thumbnails/thumbnail.png"))){ thumbnailpath = QString("Thumbnails/thumbnail.png"); } else if (store->hasFile(QString("preview.png"))) { thumbnailpath = QString("preview.png"); } if (!thumbnailpath.isEmpty()) { if (store->open(thumbnailpath)) { QByteArray bytes = store->read(store->size()); store->close(); QImage img; img.loadFromData(bytes); img.setDevicePixelRatio(devicePixelRatioF()); recentItem->setIcon(QIcon(QPixmap::fromImage(img))); } } } } + else if (fi.suffix() == "tiff" || fi.suffix() == "tif") { + // Workaround for a bug in Qt tiff QImageIO plugin + QScopedPointer doc; + doc.reset(KisPart::instance()->createDocument()); + bool r = doc->openUrl(QUrl::fromLocalFile(recentFileUrlPath), KisDocument::DontAddToRecent); + if (r) { + KisPaintDeviceSP projection = doc->image()->projection(); + recentItem->setIcon(QIcon(QPixmap::fromImage(projection->createThumbnail(48, 48, projection->exactBounds())))); + } + } else { QImage img; img.setDevicePixelRatio(devicePixelRatioF()); img.load(recentFileUrlPath); if (!img.isNull()) { recentItem->setIcon(QIcon(QPixmap::fromImage(img.scaledToWidth(48)))); } } m_thumbnailMap[recentFileUrlPath] = recentItem->icon(); } } // set the recent object with the data recentItem->setText(fileName); // what to display for the item recentItem->setToolTip(recentFileUrlPath); m_recentFilesModel.appendRow(recentItem); } // hide clear and Recent files title if there are none bool hasRecentFiles = m_mainWindow->recentFilesUrls().length() > 0; recentDocumentsLabel->setVisible(hasRecentFiles); clearRecentFilesLink->setVisible(hasRecentFiles); recentDocumentsListView->setIconSize(QSize(48, 48)); recentDocumentsListView->setModel(&m_recentFilesModel); } void KisWelcomePageWidget::dragEnterEvent(QDragEnterEvent *event) { //qDebug() << "dragEnterEvent formats" << event->mimeData()->formats() << "urls" << event->mimeData()->urls() << "has images" << event->mimeData()->hasImage(); showDropAreaIndicator(true); if (event->mimeData()->hasUrls() || event->mimeData()->hasFormat("application/x-krita-node") || event->mimeData()->hasFormat("application/x-qt-image")) { event->accept(); } } void KisWelcomePageWidget::dropEvent(QDropEvent *event) { //qDebug() << "KisWelcomePageWidget::dropEvent() formats" << event->mimeData()->formats() << "urls" << event->mimeData()->urls() << "has images" << event->mimeData()->hasImage(); 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 = m_mainWindow->installBundle(url.toLocalFile()); if (!r) { qWarning() << "Could not install bundle" << url.toLocalFile(); } } else { m_mainWindow->openDocument(url, KisMainWindow::None); } } } } void KisWelcomePageWidget::dragMoveEvent(QDragMoveEvent *event) { //qDebug() << "dragMoveEvent"; m_mainWindow->dragMoveEvent(event); if (event->mimeData()->hasUrls() || event->mimeData()->hasFormat("application/x-krita-node") || event->mimeData()->hasFormat("application/x-qt-image")) { event->accept(); } } void KisWelcomePageWidget::dragLeaveEvent(QDragLeaveEvent */*event*/) { //qDebug() << "dragLeaveEvent"; showDropAreaIndicator(false); m_mainWindow->dragLeave(); } void KisWelcomePageWidget::recentDocumentClicked(QModelIndex index) { QString fileUrl = index.data(Qt::ToolTipRole).toString(); m_mainWindow->openDocument(QUrl::fromLocalFile(fileUrl), KisMainWindow::None ); } void KisWelcomePageWidget::slotNewFileClicked() { m_mainWindow->slotFileNew(); } void KisWelcomePageWidget::slotOpenFileClicked() { m_mainWindow->slotFileOpen(); } void KisWelcomePageWidget::slotClearRecentFiles() { m_mainWindow->clearRecentFiles(); populateRecentDocuments(); } diff --git a/libs/ui/canvas/kis_canvas_updates_compressor.cpp b/libs/ui/canvas/kis_canvas_updates_compressor.cpp index e5e2769a49..8d6b5d3c97 100644 --- a/libs/ui/canvas/kis_canvas_updates_compressor.cpp +++ b/libs/ui/canvas/kis_canvas_updates_compressor.cpp @@ -1,56 +1,59 @@ /* * 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_canvas_updates_compressor.h" bool KisCanvasUpdatesCompressor::putUpdateInfo(KisUpdateInfoSP info) { const int levelOfDetail = info->levelOfDetail(); const QRect newUpdateRect = info->dirtyImageRect(); if (newUpdateRect.isEmpty()) return false; QMutexLocker l(&m_mutex); - KisUpdateInfoList::iterator it = m_updatesList.begin(); - - while (it != m_updatesList.end()) { - if (levelOfDetail == (*it)->levelOfDetail() && - newUpdateRect.contains((*it)->dirtyImageRect())) { - - /** - * We should always remove the overridden update and put 'info' to the end - * of the queue. Otherwise, the updates will become reordered and the canvas - * may have tiles artifacts with "outdated" data - */ - it = m_updatesList.erase(it); - } else { - ++it; + + if (info->canBeCompressed()) { + KisUpdateInfoList::iterator it = m_updatesList.begin(); + while (it != m_updatesList.end()) { + if ((*it)->canBeCompressed() && + levelOfDetail == (*it)->levelOfDetail() && + newUpdateRect.contains((*it)->dirtyImageRect())) { + + /** + * We should always remove the overridden update and put 'info' to the end + * of the queue. Otherwise, the updates will become reordered and the canvas + * may have tiles artifacts with "outdated" data + */ + it = m_updatesList.erase(it); + } else { + ++it; + } } } m_updatesList.append(info); return m_updatesList.size() <= 1; } void KisCanvasUpdatesCompressor::takeUpdateInfo(KisUpdateInfoList &list) { KIS_SAFE_ASSERT_RECOVER(list.isEmpty()) { list.clear(); } QMutexLocker l(&m_mutex); m_updatesList.swap(list); } diff --git a/libs/ui/canvas/kis_update_info.cpp b/libs/ui/canvas/kis_update_info.cpp index 11a23b0669..af5b3797d2 100644 --- a/libs/ui/canvas/kis_update_info.cpp +++ b/libs/ui/canvas/kis_update_info.cpp @@ -1,121 +1,131 @@ /* * Copyright (c) 2010, 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_update_info.h" /** * The connection in KisCanvas2 uses queued signals * with an argument of KisNodeSP type, so we should * register it beforehand */ struct KisUpdateInfoSPStaticRegistrar { KisUpdateInfoSPStaticRegistrar() { qRegisterMetaType("KisUpdateInfoSP"); } }; static KisUpdateInfoSPStaticRegistrar __registrar; KisUpdateInfo::KisUpdateInfo() { } KisUpdateInfo::~KisUpdateInfo() { } QRect KisUpdateInfo::dirtyViewportRect() { return QRect(); } +bool KisUpdateInfo::canBeCompressed() const +{ + return true; +} + QRect KisPPUpdateInfo::dirtyViewportRect() { return viewportRect.toAlignedRect(); } QRect KisPPUpdateInfo::dirtyImageRect() const { return dirtyImageRectVar; } int KisPPUpdateInfo::levelOfDetail() const { return 0; } KisOpenGLUpdateInfo::KisOpenGLUpdateInfo() : m_levelOfDetail(0) { } QRect KisOpenGLUpdateInfo::dirtyViewportRect() { qFatal("Not implemented yet!"); return QRect(); } void KisOpenGLUpdateInfo::assignDirtyImageRect(const QRect &rect) { m_dirtyImageRect = rect; } void KisOpenGLUpdateInfo::assignLevelOfDetail(int lod) { m_levelOfDetail = lod; } QRect KisOpenGLUpdateInfo::dirtyImageRect() const { return m_dirtyImageRect; } int KisOpenGLUpdateInfo::levelOfDetail() const { return m_levelOfDetail; } bool KisOpenGLUpdateInfo::tryMergeWith(const KisOpenGLUpdateInfo &rhs) { if (m_levelOfDetail != rhs.m_levelOfDetail) return false; // TODO: that makes the algorithm of updates compressor incorrect! m_dirtyImageRect |= rhs.m_dirtyImageRect; tileList.append(rhs.tileList); return true; } KisMarkerUpdateInfo::KisMarkerUpdateInfo(KisMarkerUpdateInfo::Type type, const QRect &dirtyImageRect) : m_type(type), m_dirtyImageRect(dirtyImageRect) { } KisMarkerUpdateInfo::Type KisMarkerUpdateInfo::type() const { return m_type; } QRect KisMarkerUpdateInfo::dirtyImageRect() const { return m_dirtyImageRect; } int KisMarkerUpdateInfo::levelOfDetail() const { // return invalid level of detail to avoid merging the update info // with other updates return -1 - (int)m_type; } + +bool KisMarkerUpdateInfo::canBeCompressed() const +{ + return false; +} diff --git a/libs/ui/canvas/kis_update_info.h b/libs/ui/canvas/kis_update_info.h index 62d29966b5..2b76e1d34b 100644 --- a/libs/ui/canvas/kis_update_info.h +++ b/libs/ui/canvas/kis_update_info.h @@ -1,168 +1,170 @@ /* * Copyright (c) 2010, 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_UPDATE_INFO_H_ #define KIS_UPDATE_INFO_H_ #include #include "kis_image_patch.h" #include "kis_shared.h" #include "kritaui_export.h" #include "opengl/kis_texture_tile_update_info.h" #include "kis_ui_types.h" class KRITAUI_EXPORT KisUpdateInfo : public KisShared { public: KisUpdateInfo(); virtual ~KisUpdateInfo(); virtual QRect dirtyViewportRect(); virtual QRect dirtyImageRect() const = 0; virtual int levelOfDetail() const = 0; + virtual bool canBeCompressed() const; }; Q_DECLARE_METATYPE(KisUpdateInfoSP) struct ConversionOptions { ConversionOptions() : m_needsConversion(false) {} ConversionOptions(const KoColorSpace *destinationColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) : m_needsConversion(true), m_destinationColorSpace(destinationColorSpace), m_renderingIntent(renderingIntent), m_conversionFlags(conversionFlags) { } bool m_needsConversion; const KoColorSpace *m_destinationColorSpace = 0; KoColorConversionTransformation::Intent m_renderingIntent; KoColorConversionTransformation::ConversionFlags m_conversionFlags; }; class KisOpenGLUpdateInfo; typedef KisSharedPtr KisOpenGLUpdateInfoSP; class KisOpenGLUpdateInfo : public KisUpdateInfo { public: KisOpenGLUpdateInfo(); KisTextureTileUpdateInfoSPList tileList; QRect dirtyViewportRect() override; QRect dirtyImageRect() const override; void assignDirtyImageRect(const QRect &rect); void assignLevelOfDetail(int lod); int levelOfDetail() const override; bool tryMergeWith(const KisOpenGLUpdateInfo& rhs); private: QRect m_dirtyImageRect; int m_levelOfDetail; }; class KisPPUpdateInfo : public KisUpdateInfo { public: enum TransferType { DIRECT, PATCH }; QRect dirtyViewportRect() override; QRect dirtyImageRect() const override; int levelOfDetail() const override; /** * The rect that was reported by KisImage as dirty */ QRect dirtyImageRectVar; /** * Rect of KisImage corresponding to @ref viewportRect . * It is cropped and aligned corresponding to the canvas. */ QRect imageRect; /** * Rect of canvas widget corresponding to @ref imageRect */ QRectF viewportRect; qreal scaleX; qreal scaleY; /** * Defines the way the source image is painted onto * prescaled QImage */ TransferType transfer; /** * Render hints for painting the direct painting/patch painting */ QPainter::RenderHints renderHints; /** * The number of additional pixels those should be added * to the patch */ qint32 borderWidth; /** * Used for temporary storage of KisImage's data * by KisProjectionCache */ KisImagePatch patch; }; class KisMarkerUpdateInfo : public KisUpdateInfo { public: enum Type { StartBatch = 0, EndBatch, BlockLodUpdates, UnblockLodUpdates, }; public: KisMarkerUpdateInfo(Type type, const QRect &dirtyImageRect); Type type() const; QRect dirtyImageRect() const override; int levelOfDetail() const override; + bool canBeCompressed() const override; private: Type m_type; QRect m_dirtyImageRect; }; #endif /* KIS_UPDATE_INFO_H_ */ diff --git a/libs/ui/dialogs/kis_dlg_filter.cpp b/libs/ui/dialogs/kis_dlg_filter.cpp index 21b861bbdd..c8294b07f8 100644 --- a/libs/ui/dialogs/kis_dlg_filter.cpp +++ b/libs/ui/dialogs/kis_dlg_filter.cpp @@ -1,249 +1,250 @@ /* * Copyright (c) 2007 Cyrille Berger * 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_dlg_filter.h" #include #include #include #include #include #include #include #include #include #include #include "kis_selection.h" #include "kis_node_commands_adapter.h" #include "kis_filter_manager.h" #include "ui_wdgfilterdialog.h" #include "kis_canvas2.h" struct KisDlgFilter::Private { Private(KisFilterManager *_filterManager, KisViewManager *_view) : currentFilter(0) , resizeCount(0) , view(_view) , filterManager(_filterManager) , blockModifyingActionsGuard(new KisInputActionGroupsMaskGuard(view->canvasBase(), ViewTransformActionGroup)) { } KisFilterSP currentFilter; Ui_FilterDialog uiFilterDialog; KisNodeSP node; int resizeCount; KisViewManager *view; KisFilterManager *filterManager; // a special guard object that blocks all the painting input actions while the // dialog is open QScopedPointer blockModifyingActionsGuard; }; KisDlgFilter::KisDlgFilter(KisViewManager *view, KisNodeSP node, KisFilterManager *filterManager, QWidget *parent) : QDialog(parent), d(new Private(filterManager, view)) { setModal(false); d->uiFilterDialog.setupUi(this); d->node = node; d->uiFilterDialog.filterSelection->setView(view); d->uiFilterDialog.filterSelection->showFilterGallery(KisConfig(true).showFilterGallery()); d->uiFilterDialog.pushButtonCreateMaskEffect->show(); connect(d->uiFilterDialog.pushButtonCreateMaskEffect, SIGNAL(pressed()), SLOT(createMask())); connect(d->uiFilterDialog.pushButtonCreateMaskEffect,SIGNAL(pressed()),SLOT(close())); d->uiFilterDialog.filterGalleryToggle->setChecked(d->uiFilterDialog.filterSelection->isFilterGalleryVisible()); d->uiFilterDialog.filterGalleryToggle->setIcon(QPixmap(":/pics/sidebaricon.png")); d->uiFilterDialog.filterGalleryToggle->setMaximumWidth(d->uiFilterDialog.filterGalleryToggle->height()); connect(d->uiFilterDialog.filterSelection, SIGNAL(sigFilterGalleryToggled(bool)), d->uiFilterDialog.filterGalleryToggle, SLOT(setChecked(bool))); connect(d->uiFilterDialog.filterGalleryToggle, SIGNAL(toggled(bool)), d->uiFilterDialog.filterSelection, SLOT(showFilterGallery(bool))); connect(d->uiFilterDialog.filterSelection, SIGNAL(sigSizeChanged()), this, SLOT(slotFilterWidgetSizeChanged())); if (node->inherits("KisMask")) { d->uiFilterDialog.pushButtonCreateMaskEffect->setVisible(false); } d->uiFilterDialog.filterSelection->setPaintDevice(true, d->node->original()); connect(d->uiFilterDialog.buttonBox, SIGNAL(accepted()), SLOT(accept())); connect(d->uiFilterDialog.buttonBox, SIGNAL(rejected()), SLOT(reject())); connect(d->uiFilterDialog.checkBoxPreview, SIGNAL(toggled(bool)), SLOT(enablePreviewToggled(bool))); connect(d->uiFilterDialog.filterSelection, SIGNAL(configurationChanged()), SLOT(filterSelectionChanged())); connect(this, SIGNAL(accepted()), SLOT(slotOnAccept())); connect(this, SIGNAL(rejected()), SLOT(slotOnReject())); KConfigGroup group( KSharedConfig::openConfig(), "filterdialog"); d->uiFilterDialog.checkBoxPreview->setChecked(group.readEntry("showPreview", true)); restoreGeometry(KisConfig(true).readEntry("filterdialog/geometry", QByteArray())); } KisDlgFilter::~KisDlgFilter() { KisConfig(false).writeEntry("filterdialog/geometry", saveGeometry()); delete d; } void KisDlgFilter::setFilter(KisFilterSP f) { Q_ASSERT(f); setDialogTitle(f); d->uiFilterDialog.filterSelection->setFilter(f); d->uiFilterDialog.pushButtonCreateMaskEffect->setEnabled(f->supportsAdjustmentLayers()); d->currentFilter = f; updatePreview(); } void KisDlgFilter::setDialogTitle(KisFilterSP filter) { setWindowTitle(filter.isNull() ? i18nc("@title:window", "Filter") : i18nc("@title:window", "Filter: %1", filter->name())); } void KisDlgFilter::startApplyingFilter(KisFilterConfigurationSP config) { if (!d->uiFilterDialog.filterSelection->configuration()) return; if (d->node->inherits("KisPaintLayer")) { config->setChannelFlags(qobject_cast(d->node.data())->channelLockFlags()); } d->filterManager->apply(config); } void KisDlgFilter::updatePreview() { KisFilterConfigurationSP config = d->uiFilterDialog.filterSelection->configuration(); if (!config) return; bool maskCreationAllowed = !d->currentFilter || d->currentFilter->configurationAllowedForMask(config); d->uiFilterDialog.pushButtonCreateMaskEffect->setEnabled(maskCreationAllowed); if (d->uiFilterDialog.checkBoxPreview->isChecked()) { KisFilterConfigurationSP config(d->uiFilterDialog.filterSelection->configuration()); startApplyingFilter(config); } d->uiFilterDialog.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); } void KisDlgFilter::adjustSize() { QWidget::adjustSize(); } void KisDlgFilter::slotFilterWidgetSizeChanged() { QMetaObject::invokeMethod(this, "adjustSize", Qt::QueuedConnection); } void KisDlgFilter::slotOnAccept() { if (!d->filterManager->isStrokeRunning()) { KisFilterConfigurationSP config(d->uiFilterDialog.filterSelection->configuration()); startApplyingFilter(config); } d->filterManager->finish(); d->uiFilterDialog.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); KisConfig(false).setShowFilterGallery(d->uiFilterDialog.filterSelection->isFilterGalleryVisible()); } void KisDlgFilter::slotOnReject() { if (d->filterManager->isStrokeRunning()) { d->filterManager->cancel(); } KisConfig(false).setShowFilterGallery(d->uiFilterDialog.filterSelection->isFilterGalleryVisible()); } void KisDlgFilter::createMask() { if (d->node->inherits("KisMask")) return; if (d->filterManager->isStrokeRunning()) { d->filterManager->cancel(); } KisLayer *layer = qobject_cast(d->node.data()); KisFilterMaskSP mask = new KisFilterMask(); mask->setName(d->currentFilter->name()); mask->initSelection(d->view->selection(), layer); mask->setFilter(d->uiFilterDialog.filterSelection->configuration()); Q_ASSERT(layer->allowAsChild(mask)); KisNodeCommandsAdapter adapter(d->view); adapter.addNode(mask, layer, layer->lastChild()); } void KisDlgFilter::enablePreviewToggled(bool state) { if (state) { updatePreview(); } else if (d->filterManager->isStrokeRunning()) { d->filterManager->cancel(); } KConfigGroup group( KSharedConfig::openConfig(), "filterdialog"); group.writeEntry("showPreview", d->uiFilterDialog.checkBoxPreview->isChecked()); group.config()->sync(); } void KisDlgFilter::filterSelectionChanged() { KisFilterSP filter = d->uiFilterDialog.filterSelection->currentFilter(); setDialogTitle(filter); + d->currentFilter = filter; d->uiFilterDialog.pushButtonCreateMaskEffect->setEnabled(filter.isNull() ? false : filter->supportsAdjustmentLayers()); updatePreview(); } void KisDlgFilter::resizeEvent(QResizeEvent* event) { QDialog::resizeEvent(event); // // Workaround, after the initialisation don't center the dialog anymore // if(d->resizeCount < 2) { // QWidget* canvas = d->view->canvas(); // QRect rect(canvas->mapToGlobal(canvas->geometry().topLeft()), size()); // int deltaX = (canvas->geometry().width() - geometry().width())/2; // int deltaY = (canvas->geometry().height() - geometry().height())/2; // rect.translate(deltaX, deltaY); // setGeometry(rect); // d->resizeCount++; // } } diff --git a/libs/ui/dialogs/kis_dlg_preferences.cc b/libs/ui/dialogs/kis_dlg_preferences.cc index 66c4fb3d60..0cb74ae846 100644 --- a/libs/ui/dialogs/kis_dlg_preferences.cc +++ b/libs/ui/dialogs/kis_dlg_preferences.cc @@ -1,1769 +1,1777 @@ /* * preferencesdlg.cc - part of KImageShop * * Copyright (c) 1999 Michael Koch * Copyright (c) 2003-2011 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_preferences.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 "KoID.h" #include #include #include #include #include #include #include #include "KisProofingConfiguration.h" #include "KoColorConversionTransformation.h" #include "kis_action_registry.h" #include #include #include "kis_clipboard.h" #include "widgets/kis_cmb_idlist.h" #include "KoColorSpace.h" #include "KoColorSpaceRegistry.h" #include "kis_action_registry.h" #include "kis_canvas_resource_provider.h" #include "kis_clipboard.h" #include "kis_color_manager.h" #include "kis_config.h" #include "kis_cursor.h" #include "kis_image_config.h" #include "kis_preference_set_registry.h" #include "widgets/kis_cmb_idlist.h" #include #include "kis_file_name_requester.h" #include #include #include #include "slider_and_spin_box_sync.h" // for the performance update #include #include #include "input/config/kis_input_configuration_page.h" #include "input/wintab/drawpile_tablettester/tablettester.h" #ifdef Q_OS_WIN #include "config_use_qt_tablet_windows.h" # ifndef USE_QT_TABLET_WINDOWS # include # endif #include "config-high-dpi-scale-factor-rounding-policy.h" #endif struct BackupSuffixValidator : public QValidator { BackupSuffixValidator(QObject *parent) : QValidator(parent) , invalidCharacters(QStringList() << "0" << "1" << "2" << "3" << "4" << "5" << "6" << "7" << "8" << "9" << "/" << "\\" << ":" << ";" << " ") {} ~BackupSuffixValidator() override {} const QStringList invalidCharacters; State validate(QString &line, int &/*pos*/) const override { Q_FOREACH(const QString invalidChar, invalidCharacters) { if (line.contains(invalidChar)) { return Invalid; } } return Acceptable; } }; GeneralTab::GeneralTab(QWidget *_parent, const char *_name) : WdgGeneralSettings(_parent, _name) { KisConfig cfg(true); // // Cursor Tab // m_cmbCursorShape->addItem(i18n("No Cursor")); m_cmbCursorShape->addItem(i18n("Tool Icon")); m_cmbCursorShape->addItem(i18n("Arrow")); m_cmbCursorShape->addItem(i18n("Small Circle")); m_cmbCursorShape->addItem(i18n("Crosshair")); m_cmbCursorShape->addItem(i18n("Triangle Righthanded")); m_cmbCursorShape->addItem(i18n("Triangle Lefthanded")); m_cmbCursorShape->addItem(i18n("Black Pixel")); m_cmbCursorShape->addItem(i18n("White Pixel")); m_cmbCursorShape->setCurrentIndex(cfg.newCursorStyle()); m_cmbOutlineShape->addItem(i18n("No Outline")); m_cmbOutlineShape->addItem(i18n("Circle Outline")); m_cmbOutlineShape->addItem(i18n("Preview Outline")); m_cmbOutlineShape->addItem(i18n("Tilt Outline")); m_cmbOutlineShape->setCurrentIndex(cfg.newOutlineStyle()); m_showOutlinePainting->setChecked(cfg.showOutlineWhilePainting()); m_changeBrushOutline->setChecked(!cfg.forceAlwaysFullSizedOutline()); KoColor cursorColor(KoColorSpaceRegistry::instance()->rgb8()); cursorColor.fromQColor(cfg.getCursorMainColor()); cursorColorBtutton->setColor(cursorColor); // // Window Tab // m_cmbMDIType->setCurrentIndex(cfg.readEntry("mdi_viewmode", (int)QMdiArea::TabbedView)); m_backgroundimage->setText(cfg.getMDIBackgroundImage()); connect(m_bnFileName, SIGNAL(clicked()), SLOT(getBackgroundImage())); connect(clearBgImageButton, SIGNAL(clicked()), SLOT(clearBackgroundImage())); QString xml = cfg.getMDIBackgroundColor(); KoColor mdiColor = KoColor::fromXML(xml); m_mdiColor->setColor(mdiColor); m_chkRubberBand->setChecked(cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); m_chkCanvasMessages->setChecked(cfg.showCanvasMessages()); const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat); m_chkHiDPI->setChecked(kritarc.value("EnableHiDPI", true).toBool()); #ifdef HAVE_HIGH_DPI_SCALE_FACTOR_ROUNDING_POLICY m_chkHiDPIFractionalScaling->setChecked(kritarc.value("EnableHiDPIFractionalScaling", true).toBool()); #else m_chkHiDPIFractionalScaling->setVisible(false); #endif chkUsageLogging->setChecked(kritarc.value("LogUsage", true).toBool()); m_chkSingleApplication->setChecked(kritarc.value("EnableSingleApplication", true).toBool()); // // Tools tab // m_radioToolOptionsInDocker->setChecked(cfg.toolOptionsInDocker()); cmbFlowMode->setCurrentIndex((int)!cfg.readEntry("useCreamyAlphaDarken", true)); m_chkSwitchSelectionCtrlAlt->setChecked(cfg.switchSelectionCtrlAlt()); chkEnableTouch->setChecked(!cfg.disableTouchOnCanvas()); chkEnableTouchRotation->setChecked(!cfg.disableTouchRotation()); chkEnableTranformToolAfterPaste->setChecked(cfg.activateTransformToolAfterPaste()); m_groupBoxKineticScrollingSettings->setChecked(cfg.kineticScrollingEnabled()); m_cmbKineticScrollingGesture->addItem(i18n("On Touch Drag")); m_cmbKineticScrollingGesture->addItem(i18n("On Click Drag")); m_cmbKineticScrollingGesture->addItem(i18n("On Middle-Click Drag")); //m_cmbKineticScrollingGesture->addItem(i18n("On Right Click Drag")); m_cmbKineticScrollingGesture->setCurrentIndex(cfg.kineticScrollingGesture()); m_kineticScrollingSensitivitySlider->setRange(0, 100); m_kineticScrollingSensitivitySlider->setValue(cfg.kineticScrollingSensitivity()); m_chkKineticScrollingHideScrollbars->setChecked(cfg.kineticScrollingHiddenScrollbars()); // // File handling // int autosaveInterval = cfg.autoSaveInterval(); //convert to minutes m_autosaveSpinBox->setValue(autosaveInterval / 60); m_autosaveCheckBox->setChecked(autosaveInterval > 0); chkHideAutosaveFiles->setChecked(cfg.readEntry("autosavefileshidden", true)); m_chkCompressKra->setChecked(cfg.compressKra()); chkZip64->setChecked(cfg.useZip64()); m_backupFileCheckBox->setChecked(cfg.backupFile()); cmbBackupFileLocation->setCurrentIndex(cfg.readEntry("backupfilelocation", 0)); txtBackupFileSuffix->setText(cfg.readEntry("backupfilesuffix", "~")); QValidator *validator = new BackupSuffixValidator(txtBackupFileSuffix); txtBackupFileSuffix->setValidator(validator); intNumBackupFiles->setValue(cfg.readEntry("numberofbackupfiles", 1)); // // Miscellaneous // cmbStartupSession->addItem(i18n("Open default window")); cmbStartupSession->addItem(i18n("Load previous session")); cmbStartupSession->addItem(i18n("Show session manager")); cmbStartupSession->setCurrentIndex(cfg.sessionOnStartup()); chkSaveSessionOnQuit->setChecked(cfg.saveSessionOnQuit(false)); m_chkConvertOnImport->setChecked(cfg.convertToImageColorspaceOnImport()); m_undoStackSize->setValue(cfg.undoStackLimit()); m_favoritePresetsSpinBox->setValue(cfg.favoritePresets()); chkShowRootLayer->setChecked(cfg.showRootLayer()); KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); bool dontUseNative = true; #ifdef Q_OS_UNIX if (qgetenv("XDG_CURRENT_DESKTOP") == "KDE") { dontUseNative = false; } #endif #ifdef Q_OS_WIN dontUseNative = false; #endif m_chkNativeFileDialog->setChecked(!group.readEntry("DontUseNativeFileDialog", dontUseNative)); intMaxBrushSize->setValue(cfg.readEntry("maximumBrushSize", 1000)); // // Resources // m_urlCacheDbLocation->setMode(KoFileDialog::OpenDirectory); m_urlCacheDbLocation->setConfigurationName("cachedb_location"); m_urlCacheDbLocation->setFileName(cfg.readEntry(KisResourceCacheDb::dbLocationKey, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation))); m_urlResourceFolder->setMode(KoFileDialog::OpenDirectory); m_urlResourceFolder->setConfigurationName("resource_directory"); m_urlResourceFolder->setFileName(cfg.readEntry(KisResourceLocator::resourceLocationKey, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation))); } void GeneralTab::setDefault() { KisConfig cfg(true); m_cmbCursorShape->setCurrentIndex(cfg.newCursorStyle(true)); m_cmbOutlineShape->setCurrentIndex(cfg.newOutlineStyle(true)); chkShowRootLayer->setChecked(cfg.showRootLayer(true)); m_autosaveCheckBox->setChecked(cfg.autoSaveInterval(true) > 0); //convert to minutes m_autosaveSpinBox->setValue(cfg.autoSaveInterval(true) / 60); chkHideAutosaveFiles->setChecked(true); m_undoStackSize->setValue(cfg.undoStackLimit(true)); m_backupFileCheckBox->setChecked(cfg.backupFile(true)); cmbBackupFileLocation->setCurrentIndex(0); txtBackupFileSuffix->setText("~"); intNumBackupFiles->setValue(1); m_showOutlinePainting->setChecked(cfg.showOutlineWhilePainting(true)); m_changeBrushOutline->setChecked(!cfg.forceAlwaysFullSizedOutline(true)); m_chkNativeFileDialog->setChecked(false); intMaxBrushSize->setValue(1000); m_cmbMDIType->setCurrentIndex((int)QMdiArea::TabbedView); m_chkRubberBand->setChecked(cfg.useOpenGL(true)); m_favoritePresetsSpinBox->setValue(cfg.favoritePresets(true)); KoColor mdiColor; mdiColor.fromXML(cfg.getMDIBackgroundColor(true)); m_mdiColor->setColor(mdiColor); m_backgroundimage->setText(cfg.getMDIBackgroundImage(true)); m_chkCanvasMessages->setChecked(cfg.showCanvasMessages(true)); m_chkCompressKra->setChecked(cfg.compressKra(true)); chkZip64->setChecked(cfg.useZip64(true)); m_chkHiDPI->setChecked(false); m_chkSingleApplication->setChecked(true); m_chkHiDPI->setChecked(true); #ifdef HAVE_HIGH_DPI_SCALE_FACTOR_ROUNDING_POLICY m_chkHiDPIFractionalScaling->setChecked(true); #endif chkUsageLogging->setChecked(true); m_radioToolOptionsInDocker->setChecked(cfg.toolOptionsInDocker(true)); cmbFlowMode->setCurrentIndex(0); m_groupBoxKineticScrollingSettings->setChecked(cfg.kineticScrollingEnabled(true)); m_cmbKineticScrollingGesture->setCurrentIndex(cfg.kineticScrollingGesture(true)); m_kineticScrollingSensitivitySlider->setValue(cfg.kineticScrollingSensitivity(true)); m_chkKineticScrollingHideScrollbars->setChecked(cfg.kineticScrollingHiddenScrollbars(true)); m_chkSwitchSelectionCtrlAlt->setChecked(cfg.switchSelectionCtrlAlt(true)); chkEnableTouch->setChecked(!cfg.disableTouchOnCanvas(true)); chkEnableTouchRotation->setChecked(!cfg.disableTouchRotation(true)); chkEnableTranformToolAfterPaste->setChecked(cfg.activateTransformToolAfterPaste(true)); m_chkConvertOnImport->setChecked(cfg.convertToImageColorspaceOnImport(true)); KoColor cursorColor(KoColorSpaceRegistry::instance()->rgb8()); cursorColor.fromQColor(cfg.getCursorMainColor(true)); cursorColorBtutton->setColor(cursorColor); m_urlCacheDbLocation->setFileName(cfg.readEntry(KisResourceCacheDb::dbLocationKey, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation))); m_urlResourceFolder->setFileName(cfg.readEntry(KisResourceLocator::resourceLocationKey, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation))); } CursorStyle GeneralTab::cursorStyle() { return (CursorStyle)m_cmbCursorShape->currentIndex(); } OutlineStyle GeneralTab::outlineStyle() { return (OutlineStyle)m_cmbOutlineShape->currentIndex(); } KisConfig::SessionOnStartup GeneralTab::sessionOnStartup() const { return (KisConfig::SessionOnStartup)cmbStartupSession->currentIndex(); } bool GeneralTab::saveSessionOnQuit() const { return chkSaveSessionOnQuit->isChecked(); } bool GeneralTab::showRootLayer() { return chkShowRootLayer->isChecked(); } int GeneralTab::autoSaveInterval() { //convert to seconds return m_autosaveCheckBox->isChecked() ? m_autosaveSpinBox->value() * 60 : 0; } int GeneralTab::undoStackSize() { return m_undoStackSize->value(); } bool GeneralTab::showOutlineWhilePainting() { return m_showOutlinePainting->isChecked(); } int GeneralTab::mdiMode() { return m_cmbMDIType->currentIndex(); } int GeneralTab::favoritePresets() { return m_favoritePresetsSpinBox->value(); } bool GeneralTab::showCanvasMessages() { return m_chkCanvasMessages->isChecked(); } bool GeneralTab::compressKra() { return m_chkCompressKra->isChecked(); } bool GeneralTab::useZip64() { return chkZip64->isChecked(); } bool GeneralTab::toolOptionsInDocker() { return m_radioToolOptionsInDocker->isChecked(); } bool GeneralTab::kineticScrollingEnabled() { return m_groupBoxKineticScrollingSettings->isChecked(); } int GeneralTab::kineticScrollingGesture() { return m_cmbKineticScrollingGesture->currentIndex(); } int GeneralTab::kineticScrollingSensitivity() { return m_kineticScrollingSensitivitySlider->value(); } bool GeneralTab::kineticScrollingHiddenScrollbars() { return m_chkKineticScrollingHideScrollbars->isChecked(); } bool GeneralTab::switchSelectionCtrlAlt() { return m_chkSwitchSelectionCtrlAlt->isChecked(); } bool GeneralTab::convertToImageColorspaceOnImport() { return m_chkConvertOnImport->isChecked(); } void GeneralTab::getBackgroundImage() { KoFileDialog dialog(this, KoFileDialog::OpenFile, "BackgroundImages"); dialog.setCaption(i18n("Select a Background Image")); dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); dialog.setImageFilters(); QString fn = dialog.filename(); // dialog box was canceled or somehow no file was selected if (fn.isEmpty()) { return; } QImage image(fn); if (image.isNull()) { QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("%1 is not a valid image file!", fn)); } else { m_backgroundimage->setText(fn); } } void GeneralTab::clearBackgroundImage() { // clearing the background image text will implicitly make the background color be used m_backgroundimage->setText(""); } #include "kactioncollection.h" #include "KisActionsSnapshot.h" ShortcutSettingsTab::ShortcutSettingsTab(QWidget *parent, const char *name) : QWidget(parent) { setObjectName(name); QGridLayout * l = new QGridLayout(this); l->setMargin(0); m_page = new WdgShortcutSettings(this); l->addWidget(m_page, 0, 0); m_snapshot.reset(new KisActionsSnapshot); KActionCollection *collection = KisPart::instance()->currentMainwindow()->actionCollection(); Q_FOREACH (QAction *action, collection->actions()) { m_snapshot->addAction(action->objectName(), action); } QMap sortedCollections = m_snapshot->actionCollections(); for (auto it = sortedCollections.constBegin(); it != sortedCollections.constEnd(); ++it) { m_page->addCollection(it.value(), it.key()); } } ShortcutSettingsTab::~ShortcutSettingsTab() { } void ShortcutSettingsTab::setDefault() { m_page->allDefault(); } void ShortcutSettingsTab::saveChanges() { m_page->save(); KisActionRegistry::instance()->settingsPageSaved(); } void ShortcutSettingsTab::cancelChanges() { m_page->undo(); } ColorSettingsTab::ColorSettingsTab(QWidget *parent, const char *name) : QWidget(parent) { setObjectName(name); // XXX: Make sure only profiles that fit the specified color model // are shown in the profile combos QGridLayout * l = new QGridLayout(this); l->setMargin(0); m_page = new WdgColorSettings(this); l->addWidget(m_page, 0, 0); KisConfig cfg(true); m_page->chkUseSystemMonitorProfile->setChecked(cfg.useSystemMonitorProfile()); connect(m_page->chkUseSystemMonitorProfile, SIGNAL(toggled(bool)), this, SLOT(toggleAllowMonitorProfileSelection(bool))); m_page->cmbWorkingColorSpace->setIDList(KoColorSpaceRegistry::instance()->listKeys()); m_page->cmbWorkingColorSpace->setCurrent(cfg.workingColorSpace()); m_page->bnAddColorProfile->setIcon(KisIconUtils::loadIcon("document-open")); m_page->bnAddColorProfile->setToolTip( i18n("Open Color Profile") ); connect(m_page->bnAddColorProfile, SIGNAL(clicked()), SLOT(installProfile())); QFormLayout *monitorProfileGrid = new QFormLayout(m_page->monitorprofileholder); for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { QLabel *lbl = new QLabel(i18nc("The number of the screen", "Screen %1:", i + 1)); m_monitorProfileLabels << lbl; KisSqueezedComboBox *cmb = new KisSqueezedComboBox(); cmb->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); monitorProfileGrid->addRow(lbl, cmb); m_monitorProfileWidgets << cmb; } // disable if not Linux as KisColorManager is not yet implemented outside Linux #ifndef Q_OS_LINUX m_page->chkUseSystemMonitorProfile->setChecked(false); m_page->chkUseSystemMonitorProfile->setDisabled(true); m_page->chkUseSystemMonitorProfile->setHidden(true); #endif refillMonitorProfiles(KoID("RGBA")); for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { if (m_monitorProfileWidgets[i]->contains(cfg.monitorProfile(i))) { m_monitorProfileWidgets[i]->setCurrent(cfg.monitorProfile(i)); } } m_page->chkBlackpoint->setChecked(cfg.useBlackPointCompensation()); m_page->chkAllowLCMSOptimization->setChecked(cfg.allowLCMSOptimization()); m_page->chkForcePaletteColor->setChecked(cfg.forcePaletteColors()); KisImageConfig cfgImage(true); KisProofingConfigurationSP proofingConfig = cfgImage.defaultProofingconfiguration(); m_page->sldAdaptationState->setMaximum(20); m_page->sldAdaptationState->setMinimum(0); m_page->sldAdaptationState->setValue((int)proofingConfig->adaptationState*20); //probably this should become the screenprofile? KoColor ga(KoColorSpaceRegistry::instance()->rgb8()); ga.fromKoColor(proofingConfig->warningColor); m_page->gamutAlarm->setColor(ga); const KoColorSpace *proofingSpace = KoColorSpaceRegistry::instance()->colorSpace(proofingConfig->proofingModel, proofingConfig->proofingDepth, proofingConfig->proofingProfile); if (proofingSpace) { m_page->proofingSpaceSelector->setCurrentColorSpace(proofingSpace); } m_page->cmbProofingIntent->setCurrentIndex((int)proofingConfig->intent); m_page->ckbProofBlackPoint->setChecked(proofingConfig->conversionFlags.testFlag(KoColorConversionTransformation::BlackpointCompensation)); m_pasteBehaviourGroup.addButton(m_page->radioPasteWeb, PASTE_ASSUME_WEB); m_pasteBehaviourGroup.addButton(m_page->radioPasteMonitor, PASTE_ASSUME_MONITOR); m_pasteBehaviourGroup.addButton(m_page->radioPasteAsk, PASTE_ASK); QAbstractButton *button = m_pasteBehaviourGroup.button(cfg.pasteBehaviour()); Q_ASSERT(button); if (button) { button->setChecked(true); } m_page->cmbMonitorIntent->setCurrentIndex(cfg.monitorRenderIntent()); toggleAllowMonitorProfileSelection(cfg.useSystemMonitorProfile()); } void ColorSettingsTab::installProfile() { KoFileDialog dialog(this, KoFileDialog::OpenFiles, "OpenDocumentICC"); dialog.setCaption(i18n("Install Color Profiles")); dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); dialog.setMimeTypeFilters(QStringList() << "application/vnd.iccprofile", "application/vnd.iccprofile"); QStringList profileNames = dialog.filenames(); KoColorSpaceEngine *iccEngine = KoColorSpaceEngineRegistry::instance()->get("icc"); Q_ASSERT(iccEngine); QString saveLocation = KoResourcePaths::saveLocation("icc_profiles"); Q_FOREACH (const QString &profileName, profileNames) { if (!QFile::copy(profileName, saveLocation + QFileInfo(profileName).fileName())) { qWarning() << "Could not install profile!" << saveLocation + QFileInfo(profileName).fileName(); continue; } iccEngine->addProfile(saveLocation + QFileInfo(profileName).fileName()); } KisConfig cfg(true); refillMonitorProfiles(KoID("RGBA")); for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { if (m_monitorProfileWidgets[i]->contains(cfg.monitorProfile(i))) { m_monitorProfileWidgets[i]->setCurrent(cfg.monitorProfile(i)); } } } void ColorSettingsTab::toggleAllowMonitorProfileSelection(bool useSystemProfile) { KisConfig cfg(true); if (useSystemProfile) { QStringList devices = KisColorManager::instance()->devices(); if (devices.size() == QApplication::desktop()->screenCount()) { for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { m_monitorProfileWidgets[i]->clear(); QString monitorForScreen = cfg.monitorForScreen(i, devices[i]); Q_FOREACH (const QString &device, devices) { m_monitorProfileLabels[i]->setText(i18nc("The display/screen we got from Qt", "Screen %1:", i + 1)); m_monitorProfileWidgets[i]->addSqueezedItem(KisColorManager::instance()->deviceName(device), device); if (devices[i] == monitorForScreen) { m_monitorProfileWidgets[i]->setCurrentIndex(i); } } } } } else { refillMonitorProfiles(KoID("RGBA")); for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { if (m_monitorProfileWidgets[i]->contains(cfg.monitorProfile(i))) { m_monitorProfileWidgets[i]->setCurrent(cfg.monitorProfile(i)); } } } } void ColorSettingsTab::setDefault() { m_page->cmbWorkingColorSpace->setCurrent("RGBA"); refillMonitorProfiles(KoID("RGBA")); KisConfig cfg(true); KisImageConfig cfgImage(true); KisProofingConfigurationSP proofingConfig = cfgImage.defaultProofingconfiguration(); const KoColorSpace *proofingSpace = KoColorSpaceRegistry::instance()->colorSpace(proofingConfig->proofingModel,proofingConfig->proofingDepth,proofingConfig->proofingProfile); if (proofingSpace) { m_page->proofingSpaceSelector->setCurrentColorSpace(proofingSpace); } m_page->cmbProofingIntent->setCurrentIndex((int)proofingConfig->intent); m_page->ckbProofBlackPoint->setChecked(proofingConfig->conversionFlags.testFlag(KoColorConversionTransformation::BlackpointCompensation)); m_page->sldAdaptationState->setValue(0); //probably this should become the screenprofile? KoColor ga(KoColorSpaceRegistry::instance()->rgb8()); ga.fromKoColor(proofingConfig->warningColor); m_page->gamutAlarm->setColor(ga); m_page->chkBlackpoint->setChecked(cfg.useBlackPointCompensation(true)); m_page->chkAllowLCMSOptimization->setChecked(cfg.allowLCMSOptimization(true)); m_page->chkForcePaletteColor->setChecked(cfg.forcePaletteColors(true)); m_page->cmbMonitorIntent->setCurrentIndex(cfg.monitorRenderIntent(true)); m_page->chkUseSystemMonitorProfile->setChecked(cfg.useSystemMonitorProfile(true)); QAbstractButton *button = m_pasteBehaviourGroup.button(cfg.pasteBehaviour(true)); Q_ASSERT(button); if (button) { button->setChecked(true); } } void ColorSettingsTab::refillMonitorProfiles(const KoID & colorSpaceId) { for (int i = 0; i < QApplication::desktop()->screenCount(); ++i) { m_monitorProfileWidgets[i]->clear(); } QMap profileList; Q_FOREACH(const KoColorProfile *profile, KoColorSpaceRegistry::instance()->profilesFor(colorSpaceId.id())) { profileList[profile->name()] = profile; } Q_FOREACH (const KoColorProfile *profile, profileList.values()) { //qDebug() << "Profile" << profile->name() << profile->isSuitableForDisplay() << csf->defaultProfile(); if (profile->isSuitableForDisplay()) { for (int i = 0; i < QApplication::desktop()->screenCount(); ++i) { m_monitorProfileWidgets[i]->addSqueezedItem(profile->name()); } } } for (int i = 0; i < QApplication::desktop()->screenCount(); ++i) { m_monitorProfileLabels[i]->setText(i18nc("The number of the screen", "Screen %1:", i + 1)); m_monitorProfileWidgets[i]->setCurrent(KoColorSpaceRegistry::instance()->defaultProfileForColorSpace(colorSpaceId.id())); } } //--------------------------------------------------------------------------------------------------- void TabletSettingsTab::setDefault() { KisCubicCurve curve; curve.fromString(DEFAULT_CURVE_STRING); m_page->pressureCurve->setCurve(curve); m_page->chkUseRightMiddleClickWorkaround->setChecked( KisConfig(true).useRightMiddleTabletButtonWorkaround(true)); #if defined Q_OS_WIN && (!defined USE_QT_TABLET_WINDOWS || defined QT_HAS_WINTAB_SWITCH) #ifdef USE_QT_TABLET_WINDOWS // ask Qt if WinInk is actually available const bool isWinInkAvailable = true; #else const bool isWinInkAvailable = KisTabletSupportWin8::isAvailable(); #endif if (isWinInkAvailable) { KisConfig cfg(true); m_page->radioWintab->setChecked(!cfg.useWin8PointerInput(true)); m_page->radioWin8PointerInput->setChecked(cfg.useWin8PointerInput(true)); } else { m_page->radioWintab->setChecked(true); m_page->radioWin8PointerInput->setChecked(false); } #else m_page->grpTabletApi->setVisible(false); #endif } TabletSettingsTab::TabletSettingsTab(QWidget* parent, const char* name): QWidget(parent) { setObjectName(name); QGridLayout * l = new QGridLayout(this); l->setMargin(0); m_page = new WdgTabletSettings(this); l->addWidget(m_page, 0, 0); KisConfig cfg(true); KisCubicCurve curve; curve.fromString( cfg.pressureTabletCurve() ); m_page->pressureCurve->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)); m_page->pressureCurve->setCurve(curve); m_page->chkUseRightMiddleClickWorkaround->setChecked( cfg.useRightMiddleTabletButtonWorkaround()); #if defined Q_OS_WIN && (!defined USE_QT_TABLET_WINDOWS || defined QT_HAS_WINTAB_SWITCH) #ifdef USE_QT_TABLET_WINDOWS // ask Qt if WinInk is actually available const bool isWinInkAvailable = true; #else const bool isWinInkAvailable = KisTabletSupportWin8::isAvailable(); #endif if (isWinInkAvailable) { m_page->radioWintab->setChecked(!cfg.useWin8PointerInput()); m_page->radioWin8PointerInput->setChecked(cfg.useWin8PointerInput()); } else { m_page->radioWintab->setChecked(true); m_page->radioWin8PointerInput->setChecked(false); m_page->grpTabletApi->setVisible(false); } #ifdef USE_QT_TABLET_WINDOWS connect(m_page->btnResolutionSettings, SIGNAL(clicked()), SLOT(slotResolutionSettings())); connect(m_page->radioWintab, SIGNAL(toggled(bool)), m_page->btnResolutionSettings, SLOT(setEnabled(bool))); m_page->btnResolutionSettings->setEnabled(m_page->radioWintab->isChecked()); #else m_page->btnResolutionSettings->setVisible(false); #endif #else m_page->grpTabletApi->setVisible(false); #endif connect(m_page->btnTabletTest, SIGNAL(clicked()), SLOT(slotTabletTest())); } void TabletSettingsTab::slotTabletTest() { TabletTestDialog tabletTestDialog(this); tabletTestDialog.exec(); } #if defined Q_OS_WIN && defined USE_QT_TABLET_WINDOWS #include "KisDlgCustomTabletResolution.h" #endif void TabletSettingsTab::slotResolutionSettings() { #if defined Q_OS_WIN && defined USE_QT_TABLET_WINDOWS KisDlgCustomTabletResolution dlg(this); dlg.exec(); #endif } //--------------------------------------------------------------------------------------------------- #include "kis_acyclic_signal_connector.h" int getTotalRAM() { return KisImageConfig(true).totalRAM(); } int PerformanceTab::realTilesRAM() { return intMemoryLimit->value() - intPoolLimit->value(); } PerformanceTab::PerformanceTab(QWidget *parent, const char *name) : WdgPerformanceSettings(parent, name) { KisImageConfig cfg(true); const double totalRAM = cfg.totalRAM(); lblTotalMemory->setText(KFormat().formatByteSize(totalRAM * 1024 * 1024, 0, KFormat::IECBinaryDialect, KFormat::UnitMegaByte)); sliderMemoryLimit->setSuffix(i18n(" %")); sliderMemoryLimit->setRange(1, 100, 2); sliderMemoryLimit->setSingleStep(0.01); sliderPoolLimit->setSuffix(i18n(" %")); sliderPoolLimit->setRange(0, 20, 2); sliderMemoryLimit->setSingleStep(0.01); sliderUndoLimit->setSuffix(i18n(" %")); sliderUndoLimit->setRange(0, 50, 2); sliderMemoryLimit->setSingleStep(0.01); intMemoryLimit->setMinimumWidth(80); intPoolLimit->setMinimumWidth(80); intUndoLimit->setMinimumWidth(80); SliderAndSpinBoxSync *sync1 = new SliderAndSpinBoxSync(sliderMemoryLimit, intMemoryLimit, getTotalRAM); sync1->slotParentValueChanged(); m_syncs << sync1; SliderAndSpinBoxSync *sync2 = new SliderAndSpinBoxSync(sliderPoolLimit, intPoolLimit, std::bind(&KisIntParseSpinBox::value, intMemoryLimit)); connect(intMemoryLimit, SIGNAL(valueChanged(int)), sync2, SLOT(slotParentValueChanged())); sync2->slotParentValueChanged(); m_syncs << sync2; SliderAndSpinBoxSync *sync3 = new SliderAndSpinBoxSync(sliderUndoLimit, intUndoLimit, std::bind(&PerformanceTab::realTilesRAM, this)); connect(intPoolLimit, SIGNAL(valueChanged(int)), sync3, SLOT(slotParentValueChanged())); sync3->slotParentValueChanged(); m_syncs << sync3; sliderSwapSize->setSuffix(i18n(" GiB")); sliderSwapSize->setRange(1, 64); intSwapSize->setRange(1, 64); KisAcyclicSignalConnector *swapSizeConnector = new KisAcyclicSignalConnector(this); swapSizeConnector->connectForwardInt(sliderSwapSize, SIGNAL(valueChanged(int)), intSwapSize, SLOT(setValue(int))); swapSizeConnector->connectBackwardInt(intSwapSize, SIGNAL(valueChanged(int)), sliderSwapSize, SLOT(setValue(int))); lblSwapFileLocation->setText(cfg.swapDir()); connect(bnSwapFile, SIGNAL(clicked()), SLOT(selectSwapDir())); sliderThreadsLimit->setRange(1, QThread::idealThreadCount()); sliderFrameClonesLimit->setRange(1, QThread::idealThreadCount()); sliderFpsLimit->setRange(20, 100); sliderFpsLimit->setSuffix(i18n(" fps")); connect(sliderThreadsLimit, SIGNAL(valueChanged(int)), SLOT(slotThreadsLimitChanged(int))); connect(sliderFrameClonesLimit, SIGNAL(valueChanged(int)), SLOT(slotFrameClonesLimitChanged(int))); intCachedFramesSizeLimit->setRange(1, 10000); intCachedFramesSizeLimit->setSuffix(i18n(" px")); intCachedFramesSizeLimit->setSingleStep(1); intCachedFramesSizeLimit->setPageStep(1000); intRegionOfInterestMargin->setRange(1, 100); intRegionOfInterestMargin->setSuffix(i18n(" %")); intRegionOfInterestMargin->setSingleStep(1); intRegionOfInterestMargin->setPageStep(10); connect(chkCachedFramesSizeLimit, SIGNAL(toggled(bool)), intCachedFramesSizeLimit, SLOT(setEnabled(bool))); connect(chkUseRegionOfInterest, SIGNAL(toggled(bool)), intRegionOfInterestMargin, SLOT(setEnabled(bool))); #ifndef Q_OS_WIN // AVX workaround is needed on Windows+GCC only chkDisableAVXOptimizations->setVisible(false); #endif load(false); } PerformanceTab::~PerformanceTab() { qDeleteAll(m_syncs); } void PerformanceTab::load(bool requestDefault) { KisImageConfig cfg(true); sliderMemoryLimit->setValue(cfg.memoryHardLimitPercent(requestDefault)); sliderPoolLimit->setValue(cfg.memoryPoolLimitPercent(requestDefault)); sliderUndoLimit->setValue(cfg.memorySoftLimitPercent(requestDefault)); chkPerformanceLogging->setChecked(cfg.enablePerfLog(requestDefault)); chkProgressReporting->setChecked(cfg.enableProgressReporting(requestDefault)); sliderSwapSize->setValue(cfg.maxSwapSize(requestDefault) / 1024); lblSwapFileLocation->setText(cfg.swapDir(requestDefault)); m_lastUsedThreadsLimit = cfg.maxNumberOfThreads(requestDefault); m_lastUsedClonesLimit = cfg.frameRenderingClones(requestDefault); sliderThreadsLimit->setValue(m_lastUsedThreadsLimit); sliderFrameClonesLimit->setValue(m_lastUsedClonesLimit); sliderFpsLimit->setValue(cfg.fpsLimit(requestDefault)); { KisConfig cfg2(true); chkOpenGLFramerateLogging->setChecked(cfg2.enableOpenGLFramerateLogging(requestDefault)); chkBrushSpeedLogging->setChecked(cfg2.enableBrushSpeedLogging(requestDefault)); chkDisableVectorOptimizations->setChecked(cfg2.enableAmdVectorizationWorkaround(requestDefault)); #ifdef Q_OS_WIN chkDisableAVXOptimizations->setChecked(cfg2.disableAVXOptimizations(requestDefault)); #endif chkBackgroundCacheGeneration->setChecked(cfg2.calculateAnimationCacheInBackground(requestDefault)); } if (cfg.useOnDiskAnimationCacheSwapping(requestDefault)) { optOnDisk->setChecked(true); } else { optInMemory->setChecked(true); } chkCachedFramesSizeLimit->setChecked(cfg.useAnimationCacheFrameSizeLimit(requestDefault)); intCachedFramesSizeLimit->setValue(cfg.animationCacheFrameSizeLimit(requestDefault)); intCachedFramesSizeLimit->setEnabled(chkCachedFramesSizeLimit->isChecked()); chkUseRegionOfInterest->setChecked(cfg.useAnimationCacheRegionOfInterest(requestDefault)); intRegionOfInterestMargin->setValue(cfg.animationCacheRegionOfInterestMargin(requestDefault) * 100.0); intRegionOfInterestMargin->setEnabled(chkUseRegionOfInterest->isChecked()); } void PerformanceTab::save() { KisImageConfig cfg(false); cfg.setMemoryHardLimitPercent(sliderMemoryLimit->value()); cfg.setMemorySoftLimitPercent(sliderUndoLimit->value()); cfg.setMemoryPoolLimitPercent(sliderPoolLimit->value()); cfg.setEnablePerfLog(chkPerformanceLogging->isChecked()); cfg.setEnableProgressReporting(chkProgressReporting->isChecked()); cfg.setMaxSwapSize(sliderSwapSize->value() * 1024); cfg.setSwapDir(lblSwapFileLocation->text()); cfg.setMaxNumberOfThreads(sliderThreadsLimit->value()); cfg.setFrameRenderingClones(sliderFrameClonesLimit->value()); cfg.setFpsLimit(sliderFpsLimit->value()); { KisConfig cfg2(true); cfg2.setEnableOpenGLFramerateLogging(chkOpenGLFramerateLogging->isChecked()); cfg2.setEnableBrushSpeedLogging(chkBrushSpeedLogging->isChecked()); cfg2.setEnableAmdVectorizationWorkaround(chkDisableVectorOptimizations->isChecked()); #ifdef Q_OS_WIN cfg2.setDisableAVXOptimizations(chkDisableAVXOptimizations->isChecked()); #endif cfg2.setCalculateAnimationCacheInBackground(chkBackgroundCacheGeneration->isChecked()); } cfg.setUseOnDiskAnimationCacheSwapping(optOnDisk->isChecked()); cfg.setUseAnimationCacheFrameSizeLimit(chkCachedFramesSizeLimit->isChecked()); cfg.setAnimationCacheFrameSizeLimit(intCachedFramesSizeLimit->value()); cfg.setUseAnimationCacheRegionOfInterest(chkUseRegionOfInterest->isChecked()); cfg.setAnimationCacheRegionOfInterestMargin(intRegionOfInterestMargin->value() / 100.0); } void PerformanceTab::selectSwapDir() { KisImageConfig cfg(true); QString swapDir = cfg.swapDir(); swapDir = QFileDialog::getExistingDirectory(0, i18nc("@title:window", "Select a swap directory"), swapDir); if (swapDir.isEmpty()) { return; } lblSwapFileLocation->setText(swapDir); } void PerformanceTab::slotThreadsLimitChanged(int value) { KisSignalsBlocker b(sliderFrameClonesLimit); sliderFrameClonesLimit->setValue(qMin(m_lastUsedClonesLimit, value)); m_lastUsedThreadsLimit = value; } void PerformanceTab::slotFrameClonesLimitChanged(int value) { KisSignalsBlocker b(sliderThreadsLimit); sliderThreadsLimit->setValue(qMax(m_lastUsedThreadsLimit, value)); m_lastUsedClonesLimit = value; } //--------------------------------------------------------------------------------------------------- #include "KoColor.h" #include "opengl/KisOpenGLModeProber.h" #include "opengl/KisScreenInformationAdapter.h" #include #include QString colorSpaceString(KisSurfaceColorSpace cs, int depth) { const QString csString = #ifdef HAVE_HDR cs == KisSurfaceColorSpace::bt2020PQColorSpace ? "Rec. 2020 PQ" : cs == KisSurfaceColorSpace::scRGBColorSpace ? "Rec. 709 Linear" : #endif cs == KisSurfaceColorSpace::sRGBColorSpace ? "sRGB" : cs == KisSurfaceColorSpace::DefaultColorSpace ? "sRGB" : "Unknown Color Space"; return QString("%1 (%2 bit)").arg(csString).arg(depth); } int formatToIndex(KisConfig::RootSurfaceFormat fmt) { return fmt == KisConfig::BT2020_PQ ? 1 : fmt == KisConfig::BT709_G10 ? 2 : 0; } KisConfig::RootSurfaceFormat indexToFormat(int value) { return value == 1 ? KisConfig::BT2020_PQ : value == 2 ? KisConfig::BT709_G10 : KisConfig::BT709_G22; } DisplaySettingsTab::DisplaySettingsTab(QWidget *parent, const char *name) : WdgDisplaySettings(parent, name) { KisConfig cfg(true); const QString rendererOpenGLText = i18nc("canvas renderer", "OpenGL"); const QString rendererSoftwareText = i18nc("canvas renderer", "Software Renderer (very slow)"); #ifdef Q_OS_WIN const QString rendererOpenGLESText = i18nc("canvas renderer", "Direct3D 11 via ANGLE"); #else const QString rendererOpenGLESText = i18nc("canvas renderer", "OpenGL ES"); #endif const KisOpenGL::OpenGLRenderer renderer = KisOpenGL::getCurrentOpenGLRenderer(); lblCurrentRenderer->setText(renderer == KisOpenGL::RendererOpenGLES ? rendererOpenGLESText : renderer == KisOpenGL::RendererDesktopGL ? rendererOpenGLText : renderer == KisOpenGL::RendererSoftware ? rendererSoftwareText : i18nc("canvas renderer", "Unknown")); cmbPreferredRenderer->clear(); const KisOpenGL::OpenGLRenderers supportedRenderers = KisOpenGL::getSupportedOpenGLRenderers(); const bool onlyOneRendererSupported = supportedRenderers == KisOpenGL::RendererDesktopGL || supportedRenderers == KisOpenGL::RendererOpenGLES || supportedRenderers == KisOpenGL::RendererSoftware; if (!onlyOneRendererSupported) { QString qtPreferredRendererText; if (KisOpenGL::getQtPreferredOpenGLRenderer() == KisOpenGL::RendererOpenGLES) { qtPreferredRendererText = rendererOpenGLESText; } else if (KisOpenGL::getQtPreferredOpenGLRenderer() == KisOpenGL::RendererSoftware) { qtPreferredRendererText = rendererSoftwareText; } else { qtPreferredRendererText = rendererOpenGLText; } cmbPreferredRenderer->addItem(i18nc("canvas renderer", "Auto (%1)", qtPreferredRendererText), KisOpenGL::RendererAuto); cmbPreferredRenderer->setCurrentIndex(0); } else { cmbPreferredRenderer->setEnabled(false); } if (supportedRenderers & KisOpenGL::RendererDesktopGL) { cmbPreferredRenderer->addItem(rendererOpenGLText, KisOpenGL::RendererDesktopGL); if (KisOpenGL::getUserPreferredOpenGLRendererConfig() == KisOpenGL::RendererDesktopGL) { cmbPreferredRenderer->setCurrentIndex(cmbPreferredRenderer->count() - 1); } } #ifdef Q_OS_WIN if (supportedRenderers & KisOpenGL::RendererOpenGLES) { cmbPreferredRenderer->addItem(rendererOpenGLESText, KisOpenGL::RendererOpenGLES); if (KisOpenGL::getUserPreferredOpenGLRendererConfig() == KisOpenGL::RendererOpenGLES) { cmbPreferredRenderer->setCurrentIndex(cmbPreferredRenderer->count() - 1); } } if (supportedRenderers & KisOpenGL::RendererSoftware) { cmbPreferredRenderer->addItem(rendererSoftwareText, KisOpenGL::RendererSoftware); if (KisOpenGL::getUserPreferredOpenGLRendererConfig() == KisOpenGL::RendererSoftware) { cmbPreferredRenderer->setCurrentIndex(cmbPreferredRenderer->count() - 1); } } #endif if (!(supportedRenderers & (KisOpenGL::RendererDesktopGL | KisOpenGL::RendererOpenGLES | KisOpenGL::RendererSoftware))) { grpOpenGL->setEnabled(false); grpOpenGL->setChecked(false); chkUseTextureBuffer->setEnabled(false); chkDisableVsync->setEnabled(false); cmbFilterMode->setEnabled(false); } else { grpOpenGL->setEnabled(true); grpOpenGL->setChecked(cfg.useOpenGL()); chkUseTextureBuffer->setEnabled(cfg.useOpenGL()); chkUseTextureBuffer->setChecked(cfg.useOpenGLTextureBuffer()); chkDisableVsync->setVisible(cfg.showAdvancedOpenGLSettings()); chkDisableVsync->setEnabled(cfg.useOpenGL()); chkDisableVsync->setChecked(cfg.disableVSync()); cmbFilterMode->setEnabled(cfg.useOpenGL()); cmbFilterMode->setCurrentIndex(cfg.openGLFilteringMode()); // Don't show the high quality filtering mode if it's not available if (!KisOpenGL::supportsLoD()) { cmbFilterMode->removeItem(3); } } lblCurrentDisplayFormat->setText(""); lblCurrentRootSurfaceFormat->setText(""); lblHDRWarning->setText(""); cmbPreferedRootSurfaceFormat->addItem(colorSpaceString(KisSurfaceColorSpace::sRGBColorSpace, 8)); #ifdef HAVE_HDR cmbPreferedRootSurfaceFormat->addItem(colorSpaceString(KisSurfaceColorSpace::bt2020PQColorSpace, 10)); cmbPreferedRootSurfaceFormat->addItem(colorSpaceString(KisSurfaceColorSpace::scRGBColorSpace, 16)); #endif cmbPreferedRootSurfaceFormat->setCurrentIndex(formatToIndex(KisConfig::BT709_G22)); slotPreferredSurfaceFormatChanged(cmbPreferedRootSurfaceFormat->currentIndex()); QOpenGLContext *context = QOpenGLContext::currentContext(); if (!context) { context = QOpenGLContext::globalShareContext(); } if (context) { #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) QScreen *screen = QGuiApplication::screenAt(rect().center()); #else QScreen *screen = 0; #endif KisScreenInformationAdapter adapter(context); if (screen && adapter.isValid()) { KisScreenInformationAdapter::ScreenInfo info = adapter.infoForScreen(screen); if (info.isValid()) { QStringList toolTip; toolTip << i18n("Display Id: %1", info.screen->name()); toolTip << i18n("Display Name: %1 %2", info.screen->manufacturer(), info.screen->model()); toolTip << i18n("Min Luminance: %1", info.minLuminance); toolTip << i18n("Max Luminance: %1", info.maxLuminance); toolTip << i18n("Max Full Frame Luminance: %1", info.maxFullFrameLuminance); toolTip << i18n("Red Primary: %1, %2", info.redPrimary[0], info.redPrimary[1]); toolTip << i18n("Green Primary: %1, %2", info.greenPrimary[0], info.greenPrimary[1]); toolTip << i18n("Blue Primary: %1, %2", info.bluePrimary[0], info.bluePrimary[1]); toolTip << i18n("White Point: %1, %2", info.whitePoint[0], info.whitePoint[1]); lblCurrentDisplayFormat->setToolTip(toolTip.join('\n')); lblCurrentDisplayFormat->setText(colorSpaceString(info.colorSpace, info.bitsPerColor)); } else { lblCurrentDisplayFormat->setToolTip(""); lblCurrentDisplayFormat->setText(i18n("Unknown")); } } else { lblCurrentDisplayFormat->setToolTip(""); lblCurrentDisplayFormat->setText(i18n("Unknown")); qWarning() << "Failed to fetch display info:" << adapter.errorString(); } const QSurfaceFormat currentFormat = KisOpenGLModeProber::instance()->surfaceformatInUse(); #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) KisSurfaceColorSpace colorSpace = currentFormat.colorSpace(); #else KisSurfaceColorSpace colorSpace = KisSurfaceColorSpace::DefaultColorSpace; #endif lblCurrentRootSurfaceFormat->setText(colorSpaceString(colorSpace, currentFormat.redBufferSize())); cmbPreferedRootSurfaceFormat->setCurrentIndex(formatToIndex(cfg.rootSurfaceFormat())); connect(cmbPreferedRootSurfaceFormat, SIGNAL(currentIndexChanged(int)), SLOT(slotPreferredSurfaceFormatChanged(int))); slotPreferredSurfaceFormatChanged(cmbPreferedRootSurfaceFormat->currentIndex()); } #ifndef HAVE_HDR grpHDRSettings->setVisible(false); #endif const QStringList openglWarnings = KisOpenGL::getOpenGLWarnings(); if (openglWarnings.isEmpty()) { lblOpenGLWarnings->setVisible(false); } else { QString text(" "); text.append(i18n("Warning(s):")); text.append("
    "); Q_FOREACH (const QString &warning, openglWarnings) { text.append("
  • "); text.append(warning.toHtmlEscaped()); text.append("
  • "); } text.append("
"); lblOpenGLWarnings->setText(text); lblOpenGLWarnings->setVisible(true); } if (qApp->applicationName() == "kritasketch" || qApp->applicationName() == "kritagemini") { grpOpenGL->setVisible(false); grpOpenGL->setMaximumHeight(0); } KisImageConfig imageCfg(false); KoColor c; c.fromQColor(imageCfg.selectionOverlayMaskColor()); c.setOpacity(1.0); btnSelectionOverlayColor->setColor(c); sldSelectionOverlayOpacity->setRange(0.0, 1.0, 2); sldSelectionOverlayOpacity->setSingleStep(0.05); sldSelectionOverlayOpacity->setValue(imageCfg.selectionOverlayMaskColor().alphaF()); intCheckSize->setValue(cfg.checkSize()); chkMoving->setChecked(cfg.scrollCheckers()); KoColor ck1(KoColorSpaceRegistry::instance()->rgb8()); ck1.fromQColor(cfg.checkersColor1()); colorChecks1->setColor(ck1); KoColor ck2(KoColorSpaceRegistry::instance()->rgb8()); ck2.fromQColor(cfg.checkersColor2()); colorChecks2->setColor(ck2); KoColor cb(KoColorSpaceRegistry::instance()->rgb8()); cb.fromQColor(cfg.canvasBorderColor()); canvasBorder->setColor(cb); hideScrollbars->setChecked(cfg.hideScrollbars()); chkCurveAntialiasing->setChecked(cfg.antialiasCurves()); chkSelectionOutlineAntialiasing->setChecked(cfg.antialiasSelectionOutline()); chkChannelsAsColor->setChecked(cfg.showSingleChannelAsColor()); chkHidePopups->setChecked(cfg.hidePopups()); connect(grpOpenGL, SIGNAL(toggled(bool)), SLOT(slotUseOpenGLToggled(bool))); KoColor gridColor(KoColorSpaceRegistry::instance()->rgb8()); gridColor.fromQColor(cfg.getPixelGridColor()); pixelGridColorButton->setColor(gridColor); pixelGridDrawingThresholdBox->setValue(cfg.getPixelGridDrawingThreshold() * 100); } void DisplaySettingsTab::setDefault() { KisConfig cfg(true); cmbPreferredRenderer->setCurrentIndex(0); if (!(KisOpenGL::getSupportedOpenGLRenderers() & (KisOpenGL::RendererDesktopGL | KisOpenGL::RendererOpenGLES))) { grpOpenGL->setEnabled(false); grpOpenGL->setChecked(false); chkUseTextureBuffer->setEnabled(false); chkDisableVsync->setEnabled(false); cmbFilterMode->setEnabled(false); } else { grpOpenGL->setEnabled(true); grpOpenGL->setChecked(cfg.useOpenGL(true)); chkUseTextureBuffer->setChecked(cfg.useOpenGLTextureBuffer(true)); chkUseTextureBuffer->setEnabled(true); chkDisableVsync->setEnabled(true); chkDisableVsync->setChecked(cfg.disableVSync(true)); cmbFilterMode->setEnabled(true); cmbFilterMode->setCurrentIndex(cfg.openGLFilteringMode(true)); } chkMoving->setChecked(cfg.scrollCheckers(true)); + + KisImageConfig imageCfg(false); + KoColor c; + c.fromQColor(imageCfg.selectionOverlayMaskColor(true)); + c.setOpacity(1.0); + btnSelectionOverlayColor->setColor(c); + sldSelectionOverlayOpacity->setValue(imageCfg.selectionOverlayMaskColor(true).alphaF()); + intCheckSize->setValue(cfg.checkSize(true)); KoColor ck1(KoColorSpaceRegistry::instance()->rgb8()); ck1.fromQColor(cfg.checkersColor1(true)); colorChecks1->setColor(ck1); KoColor ck2(KoColorSpaceRegistry::instance()->rgb8()); ck2.fromQColor(cfg.checkersColor2(true)); colorChecks2->setColor(ck2); KoColor cvb(KoColorSpaceRegistry::instance()->rgb8()); cvb.fromQColor(cfg.canvasBorderColor(true)); canvasBorder->setColor(cvb); hideScrollbars->setChecked(cfg.hideScrollbars(true)); chkCurveAntialiasing->setChecked(cfg.antialiasCurves(true)); chkSelectionOutlineAntialiasing->setChecked(cfg.antialiasSelectionOutline(true)); chkChannelsAsColor->setChecked(cfg.showSingleChannelAsColor(true)); chkHidePopups->setChecked(cfg.hidePopups(true)); KoColor gridColor(KoColorSpaceRegistry::instance()->rgb8()); gridColor.fromQColor(cfg.getPixelGridColor(true)); pixelGridColorButton->setColor(gridColor); pixelGridDrawingThresholdBox->setValue(cfg.getPixelGridDrawingThreshold(true) * 100); cmbPreferedRootSurfaceFormat->setCurrentIndex(formatToIndex(KisConfig::BT709_G22)); slotPreferredSurfaceFormatChanged(cmbPreferedRootSurfaceFormat->currentIndex()); } void DisplaySettingsTab::slotUseOpenGLToggled(bool isChecked) { chkUseTextureBuffer->setEnabled(isChecked); chkDisableVsync->setEnabled(isChecked); cmbFilterMode->setEnabled(isChecked); } void DisplaySettingsTab::slotPreferredSurfaceFormatChanged(int index) { Q_UNUSED(index); QOpenGLContext *context = QOpenGLContext::currentContext(); if (context) { #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) QScreen *screen = QGuiApplication::screenAt(rect().center()); #else QScreen *screen = 0; #endif KisScreenInformationAdapter adapter(context); if (adapter.isValid()) { KisScreenInformationAdapter::ScreenInfo info = adapter.infoForScreen(screen); if (info.isValid()) { if (cmbPreferedRootSurfaceFormat->currentIndex() != formatToIndex(KisConfig::BT709_G22) && info.colorSpace == KisSurfaceColorSpace::sRGBColorSpace) { lblHDRWarning->setText(i18n("WARNING: current display doesn't support HDR rendering")); } else { lblHDRWarning->setText(""); } } } } } //--------------------------------------------------------------------------------------------------- FullscreenSettingsTab::FullscreenSettingsTab(QWidget* parent) : WdgFullscreenSettingsBase(parent) { KisConfig cfg(true); chkDockers->setChecked(cfg.hideDockersFullscreen()); chkMenu->setChecked(cfg.hideMenuFullscreen()); chkScrollbars->setChecked(cfg.hideScrollbarsFullscreen()); chkStatusbar->setChecked(cfg.hideStatusbarFullscreen()); chkTitlebar->setChecked(cfg.hideTitlebarFullscreen()); chkToolbar->setChecked(cfg.hideToolbarFullscreen()); } void FullscreenSettingsTab::setDefault() { KisConfig cfg(true); chkDockers->setChecked(cfg.hideDockersFullscreen(true)); chkMenu->setChecked(cfg.hideMenuFullscreen(true)); chkScrollbars->setChecked(cfg.hideScrollbarsFullscreen(true)); chkStatusbar->setChecked(cfg.hideStatusbarFullscreen(true)); chkTitlebar->setChecked(cfg.hideTitlebarFullscreen(true)); chkToolbar->setChecked(cfg.hideToolbarFullscreen(true)); } //--------------------------------------------------------------------------------------------------- KisDlgPreferences::KisDlgPreferences(QWidget* parent, const char* name) : KPageDialog(parent) { Q_UNUSED(name); setWindowTitle(i18n("Configure Krita")); setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::RestoreDefaults); setFaceType(KPageDialog::Tree); // General KoVBox *vbox = new KoVBox(); KPageWidgetItem *page = new KPageWidgetItem(vbox, i18n("General")); page->setObjectName("general"); page->setHeader(i18n("General")); page->setIcon(KisIconUtils::loadIcon("go-home")); m_pages << page; addPage(page); m_general = new GeneralTab(vbox); // Shortcuts vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Keyboard Shortcuts")); page->setObjectName("shortcuts"); page->setHeader(i18n("Shortcuts")); page->setIcon(KisIconUtils::loadIcon("document-export")); m_pages << page; addPage(page); m_shortcutSettings = new ShortcutSettingsTab(vbox); connect(this, SIGNAL(accepted()), m_shortcutSettings, SLOT(saveChanges())); connect(this, SIGNAL(rejected()), m_shortcutSettings, SLOT(cancelChanges())); // Canvas input settings m_inputConfiguration = new KisInputConfigurationPage(); page = addPage(m_inputConfiguration, i18n("Canvas Input Settings")); page->setHeader(i18n("Canvas Input")); page->setObjectName("canvasinput"); page->setIcon(KisIconUtils::loadIcon("configure")); m_pages << page; // Display vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Display")); page->setObjectName("display"); page->setHeader(i18n("Display")); page->setIcon(KisIconUtils::loadIcon("preferences-desktop-display")); m_pages << page; addPage(page); m_displaySettings = new DisplaySettingsTab(vbox); // Color vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Color Management")); page->setObjectName("colormanagement"); page->setHeader(i18n("Color")); page->setIcon(KisIconUtils::loadIcon("preferences-desktop-color")); m_pages << page; addPage(page); m_colorSettings = new ColorSettingsTab(vbox); // Performance vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Performance")); page->setObjectName("performance"); page->setHeader(i18n("Performance")); page->setIcon(KisIconUtils::loadIcon("applications-system")); m_pages << page; addPage(page); m_performanceSettings = new PerformanceTab(vbox); // Tablet vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Tablet settings")); page->setObjectName("tablet"); page->setHeader(i18n("Tablet")); page->setIcon(KisIconUtils::loadIcon("document-edit")); m_pages << page; addPage(page); m_tabletSettings = new TabletSettingsTab(vbox); // full-screen mode vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Canvas-only settings")); page->setObjectName("canvasonly"); page->setHeader(i18n("Canvas-only")); page->setIcon(KisIconUtils::loadIcon("folder-pictures")); m_pages << page; addPage(page); m_fullscreenSettings = new FullscreenSettingsTab(vbox); // Author profiles m_authorPage = new KoConfigAuthorPage(); page = addPage(m_authorPage, i18nc("@title:tab Author page", "Author" )); page->setObjectName("author"); page->setHeader(i18n("Author")); page->setIcon(KisIconUtils::loadIcon("im-user")); m_pages << page; QPushButton *restoreDefaultsButton = button(QDialogButtonBox::RestoreDefaults); restoreDefaultsButton->setText(i18nc("@action:button", "Restore Defaults")); connect(this, SIGNAL(accepted()), m_inputConfiguration, SLOT(saveChanges())); connect(this, SIGNAL(rejected()), m_inputConfiguration, SLOT(revertChanges())); KisPreferenceSetRegistry *preferenceSetRegistry = KisPreferenceSetRegistry::instance(); Q_FOREACH (KisAbstractPreferenceSetFactory *preferenceSetFactory, preferenceSetRegistry->values()) { KisPreferenceSet* preferenceSet = preferenceSetFactory->createPreferenceSet(); vbox = new KoVBox(); page = new KPageWidgetItem(vbox, preferenceSet->name()); page->setHeader(preferenceSet->header()); page->setIcon(preferenceSet->icon()); addPage(page); preferenceSet->setParent(vbox); preferenceSet->loadPreferences(); connect(restoreDefaultsButton, SIGNAL(clicked(bool)), preferenceSet, SLOT(loadDefaultPreferences()), Qt::UniqueConnection); connect(this, SIGNAL(accepted()), preferenceSet, SLOT(savePreferences()), Qt::UniqueConnection); } connect(restoreDefaultsButton, SIGNAL(clicked(bool)), this, SLOT(slotDefault())); KisConfig cfg(true); QString currentPageName = cfg.readEntry("KisDlgPreferences/CurrentPage"); Q_FOREACH(KPageWidgetItem *page, m_pages) { if (page->objectName() == currentPageName) { setCurrentPage(page); break; } } } KisDlgPreferences::~KisDlgPreferences() { KisConfig cfg(true); cfg.writeEntry("KisDlgPreferences/CurrentPage", currentPage()->objectName()); } void KisDlgPreferences::showEvent(QShowEvent *event){ KPageDialog::showEvent(event); button(QDialogButtonBox::Cancel)->setAutoDefault(false); button(QDialogButtonBox::Ok)->setAutoDefault(false); button(QDialogButtonBox::RestoreDefaults)->setAutoDefault(false); button(QDialogButtonBox::Cancel)->setDefault(false); button(QDialogButtonBox::Ok)->setDefault(false); button(QDialogButtonBox::RestoreDefaults)->setDefault(false); } void KisDlgPreferences::slotDefault() { if (currentPage()->objectName() == "general") { m_general->setDefault(); } else if (currentPage()->objectName() == "shortcuts") { m_shortcutSettings->setDefault(); } else if (currentPage()->objectName() == "display") { m_displaySettings->setDefault(); } else if (currentPage()->objectName() == "colormanagement") { m_colorSettings->setDefault(); } else if (currentPage()->objectName() == "performance") { m_performanceSettings->load(true); } else if (currentPage()->objectName() == "tablet") { m_tabletSettings->setDefault(); } else if (currentPage()->objectName() == "canvasonly") { m_fullscreenSettings->setDefault(); } else if (currentPage()->objectName() == "canvasinput") { m_inputConfiguration->setDefaults(); } } bool KisDlgPreferences::editPreferences() { KisDlgPreferences* dialog; dialog = new KisDlgPreferences(); bool baccept = (dialog->exec() == Accepted); if (baccept) { // General settings KisConfig cfg(false); cfg.setNewCursorStyle(dialog->m_general->cursorStyle()); cfg.setNewOutlineStyle(dialog->m_general->outlineStyle()); cfg.setShowRootLayer(dialog->m_general->showRootLayer()); cfg.setShowOutlineWhilePainting(dialog->m_general->showOutlineWhilePainting()); cfg.setForceAlwaysFullSizedOutline(!dialog->m_general->m_changeBrushOutline->isChecked()); cfg.setSessionOnStartup(dialog->m_general->sessionOnStartup()); cfg.setSaveSessionOnQuit(dialog->m_general->saveSessionOnQuit()); KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); group.writeEntry("DontUseNativeFileDialog", !dialog->m_general->m_chkNativeFileDialog->isChecked()); cfg.writeEntry("maximumBrushSize", dialog->m_general->intMaxBrushSize->value()); cfg.writeEntry("mdi_viewmode", dialog->m_general->mdiMode()); cfg.setMDIBackgroundColor(dialog->m_general->m_mdiColor->color().toXML()); cfg.setMDIBackgroundImage(dialog->m_general->m_backgroundimage->text()); cfg.setAutoSaveInterval(dialog->m_general->autoSaveInterval()); cfg.writeEntry("autosavefileshidden", dialog->m_general->chkHideAutosaveFiles->isChecked()); cfg.setBackupFile(dialog->m_general->m_backupFileCheckBox->isChecked()); cfg.writeEntry("backupfilelocation", dialog->m_general->cmbBackupFileLocation->currentIndex()); cfg.writeEntry("backupfilesuffix", dialog->m_general->txtBackupFileSuffix->text()); cfg.writeEntry("numberofbackupfiles", dialog->m_general->intNumBackupFiles->value()); cfg.setShowCanvasMessages(dialog->m_general->showCanvasMessages()); cfg.setCompressKra(dialog->m_general->compressKra()); cfg.setUseZip64(dialog->m_general->useZip64()); const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat); kritarc.setValue("EnableHiDPI", dialog->m_general->m_chkHiDPI->isChecked()); #ifdef HAVE_HIGH_DPI_SCALE_FACTOR_ROUNDING_POLICY kritarc.setValue("EnableHiDPIFractionalScaling", dialog->m_general->m_chkHiDPIFractionalScaling->isChecked()); #endif kritarc.setValue("EnableSingleApplication", dialog->m_general->m_chkSingleApplication->isChecked()); kritarc.setValue("LogUsage", dialog->m_general->chkUsageLogging->isChecked()); cfg.setToolOptionsInDocker(dialog->m_general->toolOptionsInDocker()); cfg.writeEntry("useCreamyAlphaDarken", (bool)!dialog->m_general->cmbFlowMode->currentIndex()); cfg.setKineticScrollingEnabled(dialog->m_general->kineticScrollingEnabled()); cfg.setKineticScrollingGesture(dialog->m_general->kineticScrollingGesture()); cfg.setKineticScrollingSensitivity(dialog->m_general->kineticScrollingSensitivity()); cfg.setKineticScrollingHideScrollbars(dialog->m_general->kineticScrollingHiddenScrollbars()); cfg.setSwitchSelectionCtrlAlt(dialog->m_general->switchSelectionCtrlAlt()); cfg.setDisableTouchOnCanvas(!dialog->m_general->chkEnableTouch->isChecked()); cfg.setDisableTouchRotation(!dialog->m_general->chkEnableTouchRotation->isChecked()); cfg.setActivateTransformToolAfterPaste(dialog->m_general->chkEnableTranformToolAfterPaste->isChecked()); cfg.setConvertToImageColorspaceOnImport(dialog->m_general->convertToImageColorspaceOnImport()); cfg.setUndoStackLimit(dialog->m_general->undoStackSize()); cfg.setFavoritePresets(dialog->m_general->favoritePresets()); cfg.writeEntry(KisResourceCacheDb::dbLocationKey, dialog->m_general->m_urlCacheDbLocation->fileName()); cfg.writeEntry(KisResourceLocator::resourceLocationKey, dialog->m_general->m_urlResourceFolder->fileName()); // Color settings cfg.setUseSystemMonitorProfile(dialog->m_colorSettings->m_page->chkUseSystemMonitorProfile->isChecked()); for (int i = 0; i < QApplication::desktop()->screenCount(); ++i) { if (dialog->m_colorSettings->m_page->chkUseSystemMonitorProfile->isChecked()) { int currentIndex = dialog->m_colorSettings->m_monitorProfileWidgets[i]->currentIndex(); QString monitorid = dialog->m_colorSettings->m_monitorProfileWidgets[i]->itemData(currentIndex).toString(); cfg.setMonitorForScreen(i, monitorid); } else { cfg.setMonitorProfile(i, dialog->m_colorSettings->m_monitorProfileWidgets[i]->currentUnsqueezedText(), dialog->m_colorSettings->m_page->chkUseSystemMonitorProfile->isChecked()); } } cfg.setWorkingColorSpace(dialog->m_colorSettings->m_page->cmbWorkingColorSpace->currentItem().id()); KisImageConfig cfgImage(false); cfgImage.setDefaultProofingConfig(dialog->m_colorSettings->m_page->proofingSpaceSelector->currentColorSpace(), dialog->m_colorSettings->m_page->cmbProofingIntent->currentIndex(), dialog->m_colorSettings->m_page->ckbProofBlackPoint->isChecked(), dialog->m_colorSettings->m_page->gamutAlarm->color(), (double)dialog->m_colorSettings->m_page->sldAdaptationState->value()/20); cfg.setUseBlackPointCompensation(dialog->m_colorSettings->m_page->chkBlackpoint->isChecked()); cfg.setAllowLCMSOptimization(dialog->m_colorSettings->m_page->chkAllowLCMSOptimization->isChecked()); cfg.setForcePaletteColors(dialog->m_colorSettings->m_page->chkForcePaletteColor->isChecked()); cfg.setPasteBehaviour(dialog->m_colorSettings->m_pasteBehaviourGroup.checkedId()); cfg.setRenderIntent(dialog->m_colorSettings->m_page->cmbMonitorIntent->currentIndex()); // Tablet settings cfg.setPressureTabletCurve( dialog->m_tabletSettings->m_page->pressureCurve->curve().toString() ); cfg.setUseRightMiddleTabletButtonWorkaround( dialog->m_tabletSettings->m_page->chkUseRightMiddleClickWorkaround->isChecked()); #if defined Q_OS_WIN && (!defined USE_QT_TABLET_WINDOWS || defined QT_HAS_WINTAB_SWITCH) #ifdef USE_QT_TABLET_WINDOWS // ask Qt if WinInk is actually available const bool isWinInkAvailable = true; #else const bool isWinInkAvailable = KisTabletSupportWin8::isAvailable(); #endif if (isWinInkAvailable) { cfg.setUseWin8PointerInput(dialog->m_tabletSettings->m_page->radioWin8PointerInput->isChecked()); } #endif dialog->m_performanceSettings->save(); if (!cfg.useOpenGL() && dialog->m_displaySettings->grpOpenGL->isChecked()) cfg.setCanvasState("TRY_OPENGL"); if (dialog->m_displaySettings->grpOpenGL->isChecked()) { KisOpenGL::OpenGLRenderer renderer = static_cast( dialog->m_displaySettings->cmbPreferredRenderer->itemData( dialog->m_displaySettings->cmbPreferredRenderer->currentIndex()).toInt()); KisOpenGL::setUserPreferredOpenGLRendererConfig(renderer); } else { KisOpenGL::setUserPreferredOpenGLRendererConfig(KisOpenGL::RendererNone); } cfg.setUseOpenGLTextureBuffer(dialog->m_displaySettings->chkUseTextureBuffer->isChecked()); cfg.setOpenGLFilteringMode(dialog->m_displaySettings->cmbFilterMode->currentIndex()); cfg.setDisableVSync(dialog->m_displaySettings->chkDisableVsync->isChecked()); cfg.setRootSurfaceFormat(&kritarc, indexToFormat(dialog->m_displaySettings->cmbPreferedRootSurfaceFormat->currentIndex())); cfg.setCheckSize(dialog->m_displaySettings->intCheckSize->value()); cfg.setScrollingCheckers(dialog->m_displaySettings->chkMoving->isChecked()); cfg.setCheckersColor1(dialog->m_displaySettings->colorChecks1->color().toQColor()); cfg.setCheckersColor2(dialog->m_displaySettings->colorChecks2->color().toQColor()); cfg.setCanvasBorderColor(dialog->m_displaySettings->canvasBorder->color().toQColor()); cfg.setHideScrollbars(dialog->m_displaySettings->hideScrollbars->isChecked()); KoColor c = dialog->m_displaySettings->btnSelectionOverlayColor->color(); c.setOpacity(dialog->m_displaySettings->sldSelectionOverlayOpacity->value()); cfgImage.setSelectionOverlayMaskColor(c.toQColor()); cfg.setAntialiasCurves(dialog->m_displaySettings->chkCurveAntialiasing->isChecked()); cfg.setAntialiasSelectionOutline(dialog->m_displaySettings->chkSelectionOutlineAntialiasing->isChecked()); cfg.setShowSingleChannelAsColor(dialog->m_displaySettings->chkChannelsAsColor->isChecked()); cfg.setHidePopups(dialog->m_displaySettings->chkHidePopups->isChecked()); cfg.setHideDockersFullscreen(dialog->m_fullscreenSettings->chkDockers->checkState()); cfg.setHideMenuFullscreen(dialog->m_fullscreenSettings->chkMenu->checkState()); cfg.setHideScrollbarsFullscreen(dialog->m_fullscreenSettings->chkScrollbars->checkState()); cfg.setHideStatusbarFullscreen(dialog->m_fullscreenSettings->chkStatusbar->checkState()); cfg.setHideTitlebarFullscreen(dialog->m_fullscreenSettings->chkTitlebar->checkState()); cfg.setHideToolbarFullscreen(dialog->m_fullscreenSettings->chkToolbar->checkState()); cfg.setCursorMainColor(dialog->m_general->cursorColorBtutton->color().toQColor()); cfg.setPixelGridColor(dialog->m_displaySettings->pixelGridColorButton->color().toQColor()); cfg.setPixelGridDrawingThreshold(dialog->m_displaySettings->pixelGridDrawingThresholdBox->value() / 100); dialog->m_authorPage->apply(); } delete dialog; return baccept; } diff --git a/libs/ui/kis_safe_document_loader.cpp b/libs/ui/kis_safe_document_loader.cpp index 766f116e16..ca6223d519 100644 --- a/libs/ui/kis_safe_document_loader.cpp +++ b/libs/ui/kis_safe_document_loader.cpp @@ -1,274 +1,274 @@ /* * 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_safe_document_loader.h" #include #include #include #include #include #include #include #include #include #include "KisDocument.h" #include #include "kis_signal_compressor.h" #include "KisPart.h" class FileSystemWatcherWrapper : public QObject { Q_OBJECT public: FileSystemWatcherWrapper() { connect(&m_watcher, SIGNAL(fileChanged(QString)), SIGNAL(fileChanged(QString))); connect(&m_watcher, SIGNAL(fileChanged(QString)), SLOT(slotFileChanged(QString))); } bool addPath(const QString &file) { bool result = true; const QString ufile = unifyFilePath(file); if (m_pathCount.contains(ufile)) { m_pathCount[ufile]++; } else { m_pathCount.insert(ufile, 1); result = m_watcher.addPath(ufile); } return result; } bool removePath(const QString &file) { bool result = true; const QString ufile = unifyFilePath(file); KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_pathCount.contains(ufile), false); if (m_pathCount[ufile] == 1) { m_pathCount.remove(ufile); result = m_watcher.removePath(ufile); } else { m_pathCount[ufile]--; } return result; } QStringList files() const { return m_watcher.files(); } private Q_SLOTS: void slotFileChanged(const QString &path) { // re-add the file after QSaveFile optimization if (!m_watcher.files().contains(path) && QFileInfo(path).exists()) { m_watcher.addPath(path); } } Q_SIGNALS: void fileChanged(const QString &path); private: QString unifyFilePath(const QString &path) { return QFileInfo(path).absoluteFilePath(); } private: QFileSystemWatcher m_watcher; QHash m_pathCount; }; Q_GLOBAL_STATIC(FileSystemWatcherWrapper, s_fileSystemWatcher) struct KisSafeDocumentLoader::Private { Private() : fileChangedSignalCompressor(500 /* ms */, KisSignalCompressor::POSTPONE) { } - QScopedPointer doc; + QScopedPointer doc; KisSignalCompressor fileChangedSignalCompressor; bool isLoading = false; bool fileChangedFlag = false; QString path; QString temporaryPath; qint64 initialFileSize = 0; QDateTime initialFileTimeStamp; }; KisSafeDocumentLoader::KisSafeDocumentLoader(const QString &path, QObject *parent) : QObject(parent), m_d(new Private()) { connect(s_fileSystemWatcher, SIGNAL(fileChanged(QString)), SLOT(fileChanged(QString))); connect(&m_d->fileChangedSignalCompressor, SIGNAL(timeout()), SLOT(fileChangedCompressed())); setPath(path); } KisSafeDocumentLoader::~KisSafeDocumentLoader() { if (!m_d->path.isEmpty()) { s_fileSystemWatcher->removePath(m_d->path); } delete m_d; } void KisSafeDocumentLoader::setPath(const QString &path) { if (path.isEmpty()) return; if (!m_d->path.isEmpty()) { s_fileSystemWatcher->removePath(m_d->path); } m_d->path = path; s_fileSystemWatcher->addPath(m_d->path); } void KisSafeDocumentLoader::reloadImage() { fileChangedCompressed(true); } void KisSafeDocumentLoader::fileChanged(QString path) { if (path == m_d->path) { if (s_fileSystemWatcher->files().contains(path) == false && QFileInfo(path).exists()) { //When a path is renamed it is removed, so we ought to readd it. s_fileSystemWatcher->addPath(path); } m_d->fileChangedFlag = true; m_d->fileChangedSignalCompressor.start(); } } void KisSafeDocumentLoader::fileChangedCompressed(bool sync) { if (m_d->isLoading) return; QFileInfo initialFileInfo(m_d->path); m_d->initialFileSize = initialFileInfo.size(); m_d->initialFileTimeStamp = initialFileInfo.lastModified(); // it may happen when the file is flushed by // so other application if (!m_d->initialFileSize) return; m_d->isLoading = true; m_d->fileChangedFlag = false; m_d->temporaryPath = QDir::tempPath() + QDir::separator() + QString("krita_file_layer_copy_%1_%2.%3") .arg(QApplication::applicationPid()) .arg(qrand()) .arg(initialFileInfo.suffix()); QFile::copy(m_d->path, m_d->temporaryPath); if (!sync) { QTimer::singleShot(100, this, SLOT(delayedLoadStart())); } else { QApplication::processEvents(); delayedLoadStart(); } } void KisSafeDocumentLoader::delayedLoadStart() { QFileInfo originalInfo(m_d->path); QFileInfo tempInfo(m_d->temporaryPath); bool successfullyLoaded = false; if (!m_d->fileChangedFlag && originalInfo.size() == m_d->initialFileSize && originalInfo.lastModified() == m_d->initialFileTimeStamp && tempInfo.size() == m_d->initialFileSize) { m_d->doc.reset(KisPart::instance()->createDocument()); if (m_d->path.toLower().endsWith("ora") || m_d->path.toLower().endsWith("kra")) { QScopedPointer store(KoStore::createStore(m_d->temporaryPath, KoStore::Read)); if (store && !store->bad()) { if (store->open(QString("mergedimage.png"))) { QByteArray bytes = store->read(store->size()); store->close(); QImage mergedImage; mergedImage.loadFromData(bytes); Q_ASSERT(!mergedImage.isNull()); KisImageSP image = new KisImage(0, mergedImage.width(), mergedImage.height(), KoColorSpaceRegistry::instance()->rgb8(), ""); KisPaintLayerSP layer = new KisPaintLayer(image, "", OPACITY_OPAQUE_U8); layer->paintDevice()->convertFromQImage(mergedImage, 0); image->addNode(layer, image->rootLayer()); image->initialRefreshGraph(); m_d->doc->setCurrentImage(image); successfullyLoaded = true; } else { qWarning() << "delayedLoadStart: Could not open mergedimage.png"; } } else { qWarning() << "delayedLoadStart: Store was bad"; } } else { successfullyLoaded = m_d->doc->openUrl(QUrl::fromLocalFile(m_d->temporaryPath), KisDocument::DontAddToRecent); } } else { dbgKrita << "File was modified externally. Restarting."; dbgKrita << ppVar(m_d->fileChangedFlag); dbgKrita << ppVar(m_d->initialFileSize); dbgKrita << ppVar(m_d->initialFileTimeStamp); dbgKrita << ppVar(originalInfo.size()); dbgKrita << ppVar(originalInfo.lastModified()); dbgKrita << ppVar(tempInfo.size()); } QFile::remove(m_d->temporaryPath); m_d->isLoading = false; if (!successfullyLoaded) { // Restart the attempt m_d->fileChangedSignalCompressor.start(); } else { KisPaintDeviceSP paintDevice = new KisPaintDevice(m_d->doc->image()->colorSpace()); KisPaintDeviceSP projection = m_d->doc->image()->projection(); paintDevice->makeCloneFrom(projection, projection->extent()); emit loadingFinished(paintDevice, m_d->doc->image()->xRes(), m_d->doc->image()->yRes()); } m_d->doc.reset(); } #include "kis_safe_document_loader.moc" diff --git a/libs/ui/kis_stopgradient_editor.cpp b/libs/ui/kis_stopgradient_editor.cpp index 43f4e2aebc..33a2af5429 100644 --- a/libs/ui/kis_stopgradient_editor.cpp +++ b/libs/ui/kis_stopgradient_editor.cpp @@ -1,257 +1,257 @@ /* * Copyright (c) 2004 Cyrille Berger * 2016 Sven Langkamp * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_stopgradient_editor.h" #include #include #include #include #include #include #include #include "kis_debug.h" #include /****************************** KisStopGradientEditor ******************************/ KisStopGradientEditor::KisStopGradientEditor(QWidget *parent) : QWidget(parent), m_gradient(0) { 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->setIcon(KisIconUtils::loadIcon("transform_icons_mirror_x")); buttonReverse->setToolTip(i18n("Flip Gradient")); KisIconUtils::updateIcon(buttonReverse); connect(buttonReverse, SIGNAL(pressed()), SLOT(reverse())); - buttonReverseSecond->setIcon(KisIconUtils::loadIcon("view-refresh")); + buttonReverseSecond->setIcon(KisIconUtils::loadIcon("transform_icons_mirror_x")); buttonReverseSecond->setToolTip(i18n("Flip Gradient")); KisIconUtils::updateIcon(buttonReverseSecond); connect(buttonReverseSecond, SIGNAL(clicked()), SLOT(reverse())); this->setContextMenuPolicy(Qt::CustomContextMenu); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(showContextMenu(const QPoint &))); setCompactMode(false); setGradient(0); stopChanged(-1); } KisStopGradientEditor::KisStopGradientEditor(KoStopGradientSP gradient, QWidget *parent, const char* name, const QString& caption) : 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(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(); } void KisStopGradientEditor::sortByValue( SortFlags flags = SORT_ASCENDING ) { if (!m_gradient) return; bool ascending = (flags & SORT_ASCENDING) > 0; bool evenDistribution = (flags & EVEN_DISTRIBUTION) > 0; QList stops = m_gradient->stops(); const int stopCount = stops.size(); QList sortedStops; std::sort(stops.begin(), stops.end(), KoGradientStopValueSort()); int stopIndex = 0; for (const KoGradientStop& stop : stops) { const float value = evenDistribution ? (float)stopIndex / (float)(stopCount - 1) : stop.second.toQColor().valueF(); const float position = ascending ? value : 1.f - value; if (ascending) { sortedStops.push_back(KoGradientStop(position, stop.second)); } else { sortedStops.push_front(KoGradientStop(position, stop.second)); } stopIndex++; } m_gradient->setStops(sortedStops); gradientSlider->setSelectedStop(stopCount - 1); gradientSlider->update(); emit sigGradientChanged(); } void KisStopGradientEditor::showContextMenu(const QPoint &origin) { QMenu contextMenu(i18n("Options"), this); QAction reverseValues(i18n("Reverse Values"), this); connect(&reverseValues, &QAction::triggered, this, &KisStopGradientEditor::reverse); QAction sortAscendingValues(i18n("Sort by Value"), this); connect(&sortAscendingValues, &QAction::triggered, this, [this]{ this->sortByValue(SORT_ASCENDING); } ); QAction sortAscendingDistributed(i18n("Sort by Value (Even Distribution)"), this); connect(&sortAscendingDistributed, &QAction::triggered, this, [this]{ this->sortByValue(SORT_ASCENDING | EVEN_DISTRIBUTION);} ); contextMenu.addAction(&reverseValues); contextMenu.addSeparator(); contextMenu.addAction(&sortAscendingValues); contextMenu.addAction(&sortAscendingDistributed); contextMenu.exec(mapToGlobal(origin)); } diff --git a/plugins/extensions/resourcemanager/dlg_bundle_manager.cpp b/plugins/extensions/resourcemanager/dlg_bundle_manager.cpp index a01b3e60db..3f8493e416 100644 --- a/plugins/extensions/resourcemanager/dlg_bundle_manager.cpp +++ b/plugins/extensions/resourcemanager/dlg_bundle_manager.cpp @@ -1,417 +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()) { // 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 (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(); // KisResourceBundleSP bundle = bundleServer->resourceByMD5(ba); // QMessageBox bundleFeedback; // bundleFeedback.setIcon(QMessageBox::Warning); // QString feedback = "bundlefeedback"; // if (!bundle) { // // Get it from the blacklisted bundles // 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)){ // 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(); // 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(); KisResourceBundleSP bundle; // = bundleServer->resourceByMD5(ba); if (!bundle) { // Get it from the blacklisted bundles 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")); + if (QDateTime::fromString(bundle->getMeta("created"), Qt::ISODate).isValid()) { + m_ui->lblCreated->setText(QDateTime::fromString(bundle->getMeta("created"), Qt::ISODate).toString()); + } else { + m_ui->lblCreated->setText(QDate::fromString(bundle->getMeta("created"), "dd/MM/yyyy").toString()); + } + if (QDateTime::fromString(bundle->getMeta("updated"), Qt::ISODate).isValid()) { + m_ui->lblUpdated->setText(QDateTime::fromString(bundle->getMeta("updated"), Qt::ISODate).toString()); + } else { + m_ui->lblUpdated->setText(QDate::fromString(bundle->getMeta("updated"), "dd/MM/yyyy").toString()); + } 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 == ResourceType::Gradients) { toplevel->setText(0, i18n("Gradients")); } else if (resType == ResourceType::Patterns) { toplevel->setText(0, i18n("Patterns")); } else if (resType == ResourceType::Brushes) { toplevel->setText(0, i18n("Brushes")); } else if (resType == ResourceType::Palettes) { toplevel->setText(0, i18n("Palettes")); } else if (resType == ResourceType::Workspaces) { toplevel->setText(0, i18n("Workspaces")); } else if (resType == ResourceType::PaintOpPresets) { toplevel->setText(0, i18n("Brush Presets")); } else if (resType == ResourceType::GamutMasks) { toplevel->setText(0, i18n("Gamut Masks")); } m_ui->listBundleContents->addTopLevelItem(toplevel); 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) { w->setIconSize(QSize(ICON_SIZE, ICON_SIZE)); w->setSelectionMode(QAbstractItemView::MultiSelection); 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::slotOpenResourceFolder() { if (m_actionManager) { KisAction *action = m_actionManager->actionByName("open_resources_directory"); action->trigger(); } } diff --git a/plugins/extensions/resourcemanager/resourcemanager.cpp b/plugins/extensions/resourcemanager/resourcemanager.cpp index 7b4e253449..d841a97b24 100644 --- a/plugins/extensions/resourcemanager/resourcemanager.cpp +++ b/plugins/extensions/resourcemanager/resourcemanager.cpp @@ -1,334 +1,334 @@ /* * 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 = KisBrushServerProvider::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(); } KoResourceServer* 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); } KisResourceBundleSP ResourceManager::saveBundle(const DlgCreateBundle &dlgCreateBundle) { QString bundlePath = dlgCreateBundle.saveLocation() + "/" + dlgCreateBundle.bundleName() + ".bundle"; 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) { KoResourceSP res = d->brushServer->resourceByFilename(r); newBundle->addResource(ResourceType::Brushes, res->filename(), d->brushServer->assignedTagsList(res), res->md5()); } res = dlgCreateBundle.selectedGradients(); Q_FOREACH (const QString &r, res) { KoResourceSP res = d->gradientServer->resourceByFilename(r); newBundle->addResource(ResourceType::Gradients, res->filename(), d->gradientServer->assignedTagsList(res), res->md5()); } res = dlgCreateBundle.selectedPalettes(); Q_FOREACH (const QString &r, res) { KoResourceSP res = d->paletteServer->resourceByFilename(r); newBundle->addResource(ResourceType::Palettes, res->filename(), d->paletteServer->assignedTagsList(res), res->md5()); } res = dlgCreateBundle.selectedPatterns(); Q_FOREACH (const QString &r, res) { KoResourceSP res = d->patternServer->resourceByFilename(r); newBundle->addResource(ResourceType::Patterns, res->filename(), d->patternServer->assignedTagsList(res), res->md5()); } res = dlgCreateBundle.selectedPresets(); Q_FOREACH (const QString &r, res) { KisPaintOpPresetSP preset = d->paintopServer->resourceByFilename(r); KoResourceSP res = preset; newBundle->addResource(ResourceType::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) { KisBrushSP brush = d->brushServer->resourceByFilename(brushFile); if (brush) { newBundle->addResource(ResourceType::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) { KoResourceSP res = d->workspaceServer->resourceByFilename(r); newBundle->addResource(ResourceType::Workspaces, res->filename(), d->workspaceServer->assignedTagsList(res), res->md5()); } res = dlgCreateBundle.selectedGamutMasks(); Q_FOREACH (const QString &r, res) { KoResourceSP res = d->gamutMaskServer->resourceByFilename(r); newBundle->addResource(ResourceType::GamutMasks, res->filename(), d->gamutMaskServer->assignedTagsList(res), res->md5()); } newBundle->addMeta("fileName", bundlePath); - newBundle->addMeta("created", QDate::currentDate().toString("dd/MM/yyyy")); + newBundle->addMeta("created", QDateTime::currentDateTime().toString(Qt::ISODate)); 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"); 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) { // 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/tools/tool_transform2/kis_tool_transform.cc b/plugins/tools/tool_transform2/kis_tool_transform.cc index 31e3656630..d8b0bfd777 100644 --- a/plugins/tools/tool_transform2/kis_tool_transform.cc +++ b/plugins/tools/tool_transform2/kis_tool_transform.cc @@ -1,1135 +1,1136 @@ /* * kis_tool_transform.cc -- part of Krita * * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2005 C. Boemann * Copyright (c) 2010 Marc Pegon * 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_tool_transform.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 "widgets/kis_progress_widget.h" #include "kis_transform_utils.h" #include "kis_warp_transform_strategy.h" #include "kis_cage_transform_strategy.h" #include "kis_liquify_transform_strategy.h" #include "kis_free_transform_strategy.h" #include "kis_perspective_transform_strategy.h" #include "kis_transform_mask.h" #include "kis_transform_mask_adapter.h" #include "krita_container_utils.h" #include "kis_layer_utils.h" #include #include "strokes/transform_stroke_strategy.h" KisToolTransform::KisToolTransform(KoCanvasBase * canvas) : KisTool(canvas, KisCursor::rotateCursor()) , m_workRecursively(true) , m_warpStrategy( new KisWarpTransformStrategy( dynamic_cast(canvas)->coordinatesConverter(), m_currentArgs, m_transaction)) , m_cageStrategy( new KisCageTransformStrategy( dynamic_cast(canvas)->coordinatesConverter(), m_currentArgs, m_transaction)) , m_liquifyStrategy( new KisLiquifyTransformStrategy( dynamic_cast(canvas)->coordinatesConverter(), m_currentArgs, m_transaction, canvas->resourceManager())) , m_freeStrategy( new KisFreeTransformStrategy( dynamic_cast(canvas)->coordinatesConverter(), dynamic_cast(canvas)->snapGuide(), m_currentArgs, m_transaction)) , m_perspectiveStrategy( new KisPerspectiveTransformStrategy( dynamic_cast(canvas)->coordinatesConverter(), dynamic_cast(canvas)->snapGuide(), m_currentArgs, m_transaction)) { m_canvas = dynamic_cast(canvas); Q_ASSERT(m_canvas); setObjectName("tool_transform"); useCursor(KisCursor::selectCursor()); m_optionsWidget = 0; warpAction = new KisAction(i18n("Warp")); liquifyAction = new KisAction(i18n("Liquify")); cageAction = new KisAction(i18n("Cage")); freeTransformAction = new KisAction(i18n("Free")); perspectiveAction = new KisAction(i18n("Perspective")); // extra actions for free transform that are in the tool options mirrorHorizontalAction = new KisAction(i18n("Mirror Horizontal")); mirrorVericalAction = new KisAction(i18n("Mirror Vertical")); rotateNinteyCWAction = new KisAction(i18n("Rotate 90 degrees Clockwise")); rotateNinteyCCWAction = new KisAction(i18n("Rotate 90 degrees CounterClockwise")); applyTransformation = new KisAction(i18n("Apply")); resetTransformation = new KisAction(i18n("Reset")); m_contextMenu.reset(new QMenu()); connect(m_warpStrategy.data(), SIGNAL(requestCanvasUpdate()), SLOT(canvasUpdateRequested())); connect(m_cageStrategy.data(), SIGNAL(requestCanvasUpdate()), SLOT(canvasUpdateRequested())); connect(m_liquifyStrategy.data(), SIGNAL(requestCanvasUpdate()), SLOT(canvasUpdateRequested())); connect(m_liquifyStrategy.data(), SIGNAL(requestCursorOutlineUpdate(QPointF)), SLOT(cursorOutlineUpdateRequested(QPointF))); connect(m_liquifyStrategy.data(), SIGNAL(requestUpdateOptionWidget()), SLOT(updateOptionWidget())); connect(m_freeStrategy.data(), SIGNAL(requestCanvasUpdate()), SLOT(canvasUpdateRequested())); connect(m_freeStrategy.data(), SIGNAL(requestResetRotationCenterButtons()), SLOT(resetRotationCenterButtonsRequested())); connect(m_freeStrategy.data(), SIGNAL(requestShowImageTooBig(bool)), SLOT(imageTooBigRequested(bool))); connect(m_perspectiveStrategy.data(), SIGNAL(requestCanvasUpdate()), SLOT(canvasUpdateRequested())); connect(m_perspectiveStrategy.data(), SIGNAL(requestShowImageTooBig(bool)), SLOT(imageTooBigRequested(bool))); connect(&m_changesTracker, SIGNAL(sigConfigChanged(KisToolChangesTrackerDataSP)), this, SLOT(slotTrackerChangedConfig(KisToolChangesTrackerDataSP))); } KisToolTransform::~KisToolTransform() { cancelStroke(); } void KisToolTransform::outlineChanged() { emit freeTransformChanged(); m_canvas->updateCanvas(); } void KisToolTransform::canvasUpdateRequested() { m_canvas->updateCanvas(); } void KisToolTransform::resetCursorStyle() { setFunctionalCursor(); } void KisToolTransform::resetRotationCenterButtonsRequested() { if (!m_optionsWidget) return; m_optionsWidget->resetRotationCenterButtons(); } void KisToolTransform::imageTooBigRequested(bool value) { if (!m_optionsWidget) return; m_optionsWidget->setTooBigLabelVisible(value); } KisTransformStrategyBase* KisToolTransform::currentStrategy() const { if (m_currentArgs.mode() == ToolTransformArgs::FREE_TRANSFORM) { return m_freeStrategy.data(); } else if (m_currentArgs.mode() == ToolTransformArgs::WARP) { return m_warpStrategy.data(); } else if (m_currentArgs.mode() == ToolTransformArgs::CAGE) { return m_cageStrategy.data(); } else if (m_currentArgs.mode() == ToolTransformArgs::LIQUIFY) { return m_liquifyStrategy.data(); } else /* if (m_currentArgs.mode() == ToolTransformArgs::PERSPECTIVE_4POINT) */ { return m_perspectiveStrategy.data(); } } void KisToolTransform::paint(QPainter& gc, const KoViewConverter &converter) { Q_UNUSED(converter); if (!m_strokeId || !m_transaction.rootNode()) return; QRectF newRefRect = KisTransformUtils::imageToFlake(m_canvas->coordinatesConverter(), QRectF(0.0,0.0,1.0,1.0)); if (m_refRect != newRefRect) { m_refRect = newRefRect; currentStrategy()->externalConfigChanged(); } gc.save(); if (m_optionsWidget && m_optionsWidget->showDecorations()) { gc.setOpacity(0.3); gc.fillPath(m_selectionPath, Qt::black); } gc.restore(); currentStrategy()->paint(gc); if (!m_cursorOutline.isEmpty()) { QPainterPath mappedOutline = KisTransformUtils::imageToFlakeTransform( m_canvas->coordinatesConverter()).map(m_cursorOutline); paintToolOutline(&gc, mappedOutline); } } void KisToolTransform::setFunctionalCursor() { if (overrideCursorIfNotEditable()) { return; } if (!m_strokeId) { useCursor(KisCursor::pointingHandCursor()); } else if (m_strokeId && !m_transaction.rootNode()) { // we are in the middle of stroke initialization useCursor(KisCursor::waitCursor()); } else { useCursor(currentStrategy()->getCurrentCursor()); } } void KisToolTransform::cursorOutlineUpdateRequested(const QPointF &imagePos) { QRect canvasUpdateRect; if (!m_cursorOutline.isEmpty()) { canvasUpdateRect = m_canvas->coordinatesConverter()-> imageToDocument(m_cursorOutline.boundingRect()).toAlignedRect(); } m_cursorOutline = currentStrategy()-> getCursorOutline().translated(imagePos); if (!m_cursorOutline.isEmpty()) { canvasUpdateRect |= m_canvas->coordinatesConverter()-> imageToDocument(m_cursorOutline.boundingRect()).toAlignedRect(); } if (!canvasUpdateRect.isEmpty()) { // grow rect a bit to follow interpolation fuzziness canvasUpdateRect = kisGrowRect(canvasUpdateRect, 2); m_canvas->updateCanvas(canvasUpdateRect); } } void KisToolTransform::beginActionImpl(KoPointerEvent *event, bool usePrimaryAction, KisTool::AlternateAction action) { if (!nodeEditable()) { event->ignore(); return; } if (!m_strokeId) { startStroke(m_currentArgs.mode(), false); } else { bool result = false; if (usePrimaryAction) { result = currentStrategy()->beginPrimaryAction(event); } else { result = currentStrategy()->beginAlternateAction(event, action); } if (result) { setMode(KisTool::PAINT_MODE); } } m_actuallyMoveWhileSelected = false; outlineChanged(); } void KisToolTransform::continueActionImpl(KoPointerEvent *event, bool usePrimaryAction, KisTool::AlternateAction action) { if (mode() != KisTool::PAINT_MODE) return; + if (!m_transaction.rootNode()) return; m_actuallyMoveWhileSelected = true; if (usePrimaryAction) { currentStrategy()->continuePrimaryAction(event); } else { currentStrategy()->continueAlternateAction(event, action); } updateOptionWidget(); outlineChanged(); } void KisToolTransform::endActionImpl(KoPointerEvent *event, bool usePrimaryAction, KisTool::AlternateAction action) { if (mode() != KisTool::PAINT_MODE) return; setMode(KisTool::HOVER_MODE); if (m_actuallyMoveWhileSelected || currentStrategy()->acceptsClicks()) { bool result = false; if (usePrimaryAction) { result = currentStrategy()->endPrimaryAction(event); } else { result = currentStrategy()->endAlternateAction(event, action); } if (result) { commitChanges(); } outlineChanged(); } updateOptionWidget(); updateApplyResetAvailability(); } QMenu* KisToolTransform::popupActionsMenu() { if (m_contextMenu) { m_contextMenu->clear(); m_contextMenu->addSection(i18n("Transform Tool Actions")); m_contextMenu->addSeparator(); // add a quick switch to different transform types m_contextMenu->addAction(freeTransformAction); m_contextMenu->addAction(perspectiveAction); m_contextMenu->addAction(warpAction); m_contextMenu->addAction(cageAction); m_contextMenu->addAction(liquifyAction); // extra options if free transform is selected if (transformMode() == FreeTransformMode) { m_contextMenu->addSeparator(); m_contextMenu->addAction(mirrorHorizontalAction); m_contextMenu->addAction(mirrorVericalAction); m_contextMenu->addAction(rotateNinteyCWAction); m_contextMenu->addAction(rotateNinteyCCWAction); } m_contextMenu->addSeparator(); m_contextMenu->addAction(applyTransformation); m_contextMenu->addAction(resetTransformation); } return m_contextMenu.data(); } void KisToolTransform::beginPrimaryAction(KoPointerEvent *event) { beginActionImpl(event, true, KisTool::NONE); } void KisToolTransform::continuePrimaryAction(KoPointerEvent *event) { continueActionImpl(event, true, KisTool::NONE); } void KisToolTransform::endPrimaryAction(KoPointerEvent *event) { endActionImpl(event, true, KisTool::NONE); } void KisToolTransform::activatePrimaryAction() { currentStrategy()->activatePrimaryAction(); setFunctionalCursor(); } void KisToolTransform::deactivatePrimaryAction() { currentStrategy()->deactivatePrimaryAction(); } void KisToolTransform::activateAlternateAction(AlternateAction action) { currentStrategy()->activateAlternateAction(action); setFunctionalCursor(); } void KisToolTransform::deactivateAlternateAction(AlternateAction action) { currentStrategy()->deactivateAlternateAction(action); } void KisToolTransform::beginAlternateAction(KoPointerEvent *event, AlternateAction action) { beginActionImpl(event, false, action); } void KisToolTransform::continueAlternateAction(KoPointerEvent *event, AlternateAction action) { continueActionImpl(event, false, action); } void KisToolTransform::endAlternateAction(KoPointerEvent *event, AlternateAction action) { endActionImpl(event, false, action); } void KisToolTransform::mousePressEvent(KoPointerEvent *event) { KisTool::mousePressEvent(event); } void KisToolTransform::mouseMoveEvent(KoPointerEvent *event) { QPointF mousePos = m_canvas->coordinatesConverter()->documentToImage(event->point); cursorOutlineUpdateRequested(mousePos); if (this->mode() != KisTool::PAINT_MODE) { currentStrategy()->hoverActionCommon(event); setFunctionalCursor(); KisTool::mouseMoveEvent(event); return; } } void KisToolTransform::mouseReleaseEvent(KoPointerEvent *event) { KisTool::mouseReleaseEvent(event); } void KisToolTransform::applyTransform() { slotApplyTransform(); } KisToolTransform::TransformToolMode KisToolTransform::transformMode() const { TransformToolMode mode = FreeTransformMode; switch (m_currentArgs.mode()) { case ToolTransformArgs::FREE_TRANSFORM: mode = FreeTransformMode; break; case ToolTransformArgs::WARP: mode = WarpTransformMode; break; case ToolTransformArgs::CAGE: mode = CageTransformMode; break; case ToolTransformArgs::LIQUIFY: mode = LiquifyTransformMode; break; case ToolTransformArgs::PERSPECTIVE_4POINT: mode = PerspectiveTransformMode; break; default: KIS_ASSERT_RECOVER_NOOP(0 && "unexpected transform mode"); } return mode; } double KisToolTransform::translateX() const { return m_currentArgs.transformedCenter().x(); } double KisToolTransform::translateY() const { return m_currentArgs.transformedCenter().y(); } double KisToolTransform::rotateX() const { return m_currentArgs.aX(); } double KisToolTransform::rotateY() const { return m_currentArgs.aY(); } double KisToolTransform::rotateZ() const { return m_currentArgs.aZ(); } double KisToolTransform::scaleX() const { return m_currentArgs.scaleX(); } double KisToolTransform::scaleY() const { return m_currentArgs.scaleY(); } double KisToolTransform::shearX() const { return m_currentArgs.shearX(); } double KisToolTransform::shearY() const { return m_currentArgs.shearY(); } KisToolTransform::WarpType KisToolTransform::warpType() const { switch(m_currentArgs.warpType()) { case KisWarpTransformWorker::AFFINE_TRANSFORM: return AffineWarpType; case KisWarpTransformWorker::RIGID_TRANSFORM: return RigidWarpType; case KisWarpTransformWorker::SIMILITUDE_TRANSFORM: return SimilitudeWarpType; default: return RigidWarpType; } } double KisToolTransform::warpFlexibility() const { return m_currentArgs.alpha(); } int KisToolTransform::warpPointDensity() const { return m_currentArgs.numPoints(); } void KisToolTransform::setTransformMode(KisToolTransform::TransformToolMode newMode) { ToolTransformArgs::TransformMode mode = ToolTransformArgs::FREE_TRANSFORM; switch (newMode) { case FreeTransformMode: mode = ToolTransformArgs::FREE_TRANSFORM; break; case WarpTransformMode: mode = ToolTransformArgs::WARP; break; case CageTransformMode: mode = ToolTransformArgs::CAGE; break; case LiquifyTransformMode: mode = ToolTransformArgs::LIQUIFY; break; case PerspectiveTransformMode: mode = ToolTransformArgs::PERSPECTIVE_4POINT; break; default: KIS_ASSERT_RECOVER_NOOP(0 && "unexpected transform mode"); } if( mode != m_currentArgs.mode() ) { if( newMode == FreeTransformMode ) { m_optionsWidget->slotSetFreeTransformModeButtonClicked( true ); } else if( newMode == WarpTransformMode ) { m_optionsWidget->slotSetWarpModeButtonClicked( true ); } else if( newMode == CageTransformMode ) { m_optionsWidget->slotSetCageModeButtonClicked( true ); } else if( newMode == LiquifyTransformMode ) { m_optionsWidget->slotSetLiquifyModeButtonClicked( true ); } else if( newMode == PerspectiveTransformMode ) { m_optionsWidget->slotSetPerspectiveModeButtonClicked( true ); } emit transformModeChanged(); } } void KisToolTransform::setRotateX( double rotation ) { m_currentArgs.setAX( normalizeAngle(rotation) ); } void KisToolTransform::setRotateY( double rotation ) { m_currentArgs.setAY( normalizeAngle(rotation) ); } void KisToolTransform::setRotateZ( double rotation ) { m_currentArgs.setAZ( normalizeAngle(rotation) ); } void KisToolTransform::setWarpType( KisToolTransform::WarpType type ) { switch( type ) { case RigidWarpType: m_currentArgs.setWarpType(KisWarpTransformWorker::RIGID_TRANSFORM); break; case AffineWarpType: m_currentArgs.setWarpType(KisWarpTransformWorker::AFFINE_TRANSFORM); break; case SimilitudeWarpType: m_currentArgs.setWarpType(KisWarpTransformWorker::SIMILITUDE_TRANSFORM); break; default: break; } } void KisToolTransform::setWarpFlexibility( double flexibility ) { m_currentArgs.setAlpha( flexibility ); } void KisToolTransform::setWarpPointDensity( int density ) { m_optionsWidget->slotSetWarpDensity(density); } void KisToolTransform::initTransformMode(ToolTransformArgs::TransformMode mode) { m_currentArgs = KisTransformUtils::resetArgsForMode(mode, m_currentArgs.filterId(), m_transaction); initGuiAfterTransformMode(); } void KisToolTransform::initGuiAfterTransformMode() { currentStrategy()->externalConfigChanged(); outlineChanged(); updateOptionWidget(); updateApplyResetAvailability(); setFunctionalCursor(); } void KisToolTransform::updateSelectionPath(const QPainterPath &selectionOutline) { m_selectionPath = selectionOutline; const KisCoordinatesConverter *converter = m_canvas->coordinatesConverter(); QTransform i2f = converter->imageToDocumentTransform() * converter->documentToFlakeTransform(); m_selectionPath = i2f.map(selectionOutline); } void KisToolTransform::initThumbnailImage(KisPaintDeviceSP previewDevice) { QImage origImg; m_selectedPortionCache = previewDevice; QTransform thumbToImageTransform; const int maxSize = 2000; QRect srcRect(m_transaction.originalRect().toAlignedRect()); int x, y, w, h; srcRect.getRect(&x, &y, &w, &h); if (m_selectedPortionCache) { if (w > maxSize || h > maxSize) { qreal scale = qreal(maxSize) / (w > h ? w : h); QTransform scaleTransform = QTransform::fromScale(scale, scale); QRect thumbRect = scaleTransform.mapRect(m_transaction.originalRect()).toAlignedRect(); origImg = m_selectedPortionCache-> createThumbnail(thumbRect.width(), thumbRect.height(), srcRect, 1, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); thumbToImageTransform = scaleTransform.inverted(); } else { origImg = m_selectedPortionCache->convertToQImage(0, x, y, w, h, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); thumbToImageTransform = QTransform(); } } // init both strokes since the thumbnail is initialized only once // during the stroke m_freeStrategy->setThumbnailImage(origImg, thumbToImageTransform); m_perspectiveStrategy->setThumbnailImage(origImg, thumbToImageTransform); m_warpStrategy->setThumbnailImage(origImg, thumbToImageTransform); m_cageStrategy->setThumbnailImage(origImg, thumbToImageTransform); m_liquifyStrategy->setThumbnailImage(origImg, thumbToImageTransform); } void KisToolTransform::activate(ToolActivation toolActivation, const QSet &shapes) { KisTool::activate(toolActivation, shapes); if (currentNode()) { m_transaction = TransformTransactionProperties(QRectF(), &m_currentArgs, KisNodeSP(), {}); } startStroke(ToolTransformArgs::FREE_TRANSFORM, false); } void KisToolTransform::deactivate() { endStroke(); m_canvas->updateCanvas(); KisTool::deactivate(); } void KisToolTransform::requestUndoDuringStroke() { if (!m_strokeId) return; if (m_changesTracker.isEmpty()) { cancelStroke(); } else { m_changesTracker.requestUndo(); } } void KisToolTransform::requestStrokeEnd() { endStroke(); } void KisToolTransform::requestStrokeCancellation() { if (m_currentArgs.isIdentity()) { cancelStroke(); } else { slotResetTransform(); } } void KisToolTransform::startStroke(ToolTransformArgs::TransformMode mode, bool forceReset) { Q_ASSERT(!m_strokeId); // set up and null checks before we do anything KisResourcesSnapshotSP resources = new KisResourcesSnapshot(image(), currentNode(), this->canvas()->resourceManager()); KisNodeSP currentNode = resources->currentNode(); if (!currentNode || !currentNode->isEditable()) return; m_transaction = TransformTransactionProperties(QRectF(), &m_currentArgs, KisNodeSP(), {}); m_currentArgs = ToolTransformArgs(); // some layer types cannot be transformed. Give a message and return if a user tries it if (currentNode->inherits("KisColorizeMask") || currentNode->inherits("KisFileLayer") || currentNode->inherits("KisCloneLayer")) { KisCanvas2 *kisCanvas = dynamic_cast(canvas()); kisCanvas->viewManager()-> showFloatingMessage( i18nc("floating message in transformation tool", "Layer type cannot use the transform tool"), koIcon("object-locked"), 4000, KisFloatingMessage::High); return; } if (m_optionsWidget) { m_workRecursively = m_optionsWidget->workRecursively() || !currentNode->paintDevice(); } KisSelectionSP selection = resources->activeSelection(); /** * When working with transform mask, selections are not * taken into account. */ if (selection && dynamic_cast(currentNode.data())) { KisCanvas2 *kisCanvas = dynamic_cast(canvas()); kisCanvas->viewManager()-> showFloatingMessage( i18nc("floating message in transformation tool", "Selections are not used when editing transform masks "), QIcon(), 4000, KisFloatingMessage::Low); selection = 0; } TransformStrokeStrategy *strategy = new TransformStrokeStrategy(mode, m_workRecursively, m_currentArgs.filterId(), forceReset, currentNode, selection, image().data(), image().data()); connect(strategy, SIGNAL(sigPreviewDeviceReady(KisPaintDeviceSP, QPainterPath)), SLOT(slotPreviewDeviceGenerated(KisPaintDeviceSP, QPainterPath))); connect(strategy, SIGNAL(sigTransactionGenerated(TransformTransactionProperties, ToolTransformArgs)), SLOT(slotTransactionGenerated(TransformTransactionProperties, ToolTransformArgs))); m_strokeId = image()->startStroke(strategy); KIS_SAFE_ASSERT_RECOVER_NOOP(m_changesTracker.isEmpty()); slotPreviewDeviceGenerated(0, QPainterPath()); } void KisToolTransform::endStroke() { if (!m_strokeId) return; if (!m_currentArgs.isIdentity()) { image()->addJob(m_strokeId, new TransformStrokeStrategy::TransformAllData(m_currentArgs)); image()->endStroke(m_strokeId); } else { image()->cancelStroke(m_strokeId); } m_strokeId.clear(); m_changesTracker.reset(); m_transaction = TransformTransactionProperties(QRectF(), &m_currentArgs, KisNodeSP(), {}); outlineChanged(); } void KisToolTransform::slotTransactionGenerated(TransformTransactionProperties transaction, ToolTransformArgs args) { if (transaction.transformedNodes().isEmpty()) { KisCanvas2 *kisCanvas = dynamic_cast(canvas()); kisCanvas->viewManager()-> showFloatingMessage( i18nc("floating message in transformation tool", "Cannot transform empty layer "), QIcon(), 1000, KisFloatingMessage::Medium); cancelStroke(); return; } m_transaction = transaction; m_currentArgs = args; m_transaction.setCurrentConfigLocation(&m_currentArgs); KIS_SAFE_ASSERT_RECOVER_NOOP(m_changesTracker.isEmpty()); commitChanges(); initGuiAfterTransformMode(); if (m_transaction.hasInvisibleNodes()) { KisCanvas2 *kisCanvas = dynamic_cast(canvas()); kisCanvas->viewManager()-> showFloatingMessage( i18nc("floating message in transformation tool", "Invisible sublayers will also be transformed. Lock layers if you do not want them to be transformed "), QIcon(), 4000, KisFloatingMessage::Low); } } void KisToolTransform::slotPreviewDeviceGenerated(KisPaintDeviceSP device, const QPainterPath &selectionOutline) { if (device && device->exactBounds().isEmpty()) { KisCanvas2 *kisCanvas = dynamic_cast(canvas()); kisCanvas->viewManager()-> showFloatingMessage( i18nc("floating message in transformation tool", "Cannot transform empty layer "), QIcon(), 1000, KisFloatingMessage::Medium); cancelStroke(); } else { initThumbnailImage(device); updateSelectionPath(selectionOutline); initGuiAfterTransformMode(); } } void KisToolTransform::cancelStroke() { if (!m_strokeId) return; if (m_currentArgs.continuedTransform()) { m_currentArgs.restoreContinuedState(); endStroke(); } else { image()->cancelStroke(m_strokeId); m_strokeId.clear(); m_changesTracker.reset(); m_transaction = TransformTransactionProperties(QRectF(), &m_currentArgs, KisNodeSP(), {}); outlineChanged(); } } void KisToolTransform::commitChanges() { if (!m_strokeId) return; m_changesTracker.commitConfig(toQShared(m_currentArgs.clone())); } void KisToolTransform::slotTrackerChangedConfig(KisToolChangesTrackerDataSP status) { const ToolTransformArgs *newArgs = dynamic_cast(status.data()); KIS_SAFE_ASSERT_RECOVER_RETURN(newArgs); *m_transaction.currentConfig() = *newArgs; slotUiChangedConfig(); updateOptionWidget(); } QList KisToolTransform::fetchNodesList(ToolTransformArgs::TransformMode mode, KisNodeSP root, bool recursive) { QList result; auto fetchFunc = [&result, mode, root] (KisNodeSP node) { if (node->isEditable(node == root) && (!node->inherits("KisShapeLayer") || mode == ToolTransformArgs::FREE_TRANSFORM) && !node->inherits("KisFileLayer") && (!node->inherits("KisTransformMask") || node == root)) { result << node; } }; if (recursive) { KisLayerUtils::recursiveApplyNodes(root, fetchFunc); } else { fetchFunc(root); } return result; } QWidget* KisToolTransform::createOptionWidget() { m_optionsWidget = new KisToolTransformConfigWidget(&m_transaction, m_canvas, m_workRecursively, 0); Q_CHECK_PTR(m_optionsWidget); m_optionsWidget->setObjectName(toolId() + " option widget"); // 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); connect(m_optionsWidget, SIGNAL(sigConfigChanged()), this, SLOT(slotUiChangedConfig())); connect(m_optionsWidget, SIGNAL(sigApplyTransform()), this, SLOT(slotApplyTransform())); connect(m_optionsWidget, SIGNAL(sigResetTransform()), this, SLOT(slotResetTransform())); connect(m_optionsWidget, SIGNAL(sigRestartTransform()), this, SLOT(slotRestartTransform())); connect(m_optionsWidget, SIGNAL(sigEditingFinished()), this, SLOT(slotEditingFinished())); connect(mirrorHorizontalAction, SIGNAL(triggered(bool)), m_optionsWidget, SLOT(slotFlipX())); connect(mirrorVericalAction, SIGNAL(triggered(bool)), m_optionsWidget, SLOT(slotFlipY())); connect(rotateNinteyCWAction, SIGNAL(triggered(bool)), m_optionsWidget, SLOT(slotRotateCW())); connect(rotateNinteyCCWAction, SIGNAL(triggered(bool)), m_optionsWidget, SLOT(slotRotateCCW())); connect(warpAction, SIGNAL(triggered(bool)), this, SLOT(slotUpdateToWarpType())); connect(perspectiveAction, SIGNAL(triggered(bool)), this, SLOT(slotUpdateToPerspectiveType())); connect(freeTransformAction, SIGNAL(triggered(bool)), this, SLOT(slotUpdateToFreeTransformType())); connect(liquifyAction, SIGNAL(triggered(bool)), this, SLOT(slotUpdateToLiquifyType())); connect(cageAction, SIGNAL(triggered(bool)), this, SLOT(slotUpdateToCageType())); connect(applyTransformation, SIGNAL(triggered(bool)), this, SLOT(slotApplyTransform())); connect(resetTransformation, SIGNAL(triggered(bool)), this, SLOT(slotResetTransform())); updateOptionWidget(); return m_optionsWidget; } void KisToolTransform::updateOptionWidget() { if (!m_optionsWidget) return; if (!currentNode()) { m_optionsWidget->setEnabled(false); return; } else { m_optionsWidget->setEnabled(true); m_optionsWidget->updateConfig(m_currentArgs); } } void KisToolTransform::updateApplyResetAvailability() { if (m_optionsWidget) { m_optionsWidget->setApplyResetDisabled(m_currentArgs.isIdentity()); } } void KisToolTransform::slotUiChangedConfig() { if (mode() == KisTool::PAINT_MODE) return; currentStrategy()->externalConfigChanged(); if (m_currentArgs.mode() == ToolTransformArgs::LIQUIFY) { m_currentArgs.saveLiquifyTransformMode(); } outlineChanged(); updateApplyResetAvailability(); } void KisToolTransform::slotApplyTransform() { QApplication::setOverrideCursor(KisCursor::waitCursor()); endStroke(); QApplication::restoreOverrideCursor(); } void KisToolTransform::slotResetTransform() { if (m_currentArgs.continuedTransform()) { ToolTransformArgs::TransformMode savedMode = m_currentArgs.mode(); /** * Our reset transform button can be used for two purposes: * * 1) Reset current transform to the initial one, which was * loaded from the previous user action. * * 2) Reset transform frame to infinity when the frame is unchanged */ const bool transformDiffers = !m_currentArgs.continuedTransform()->isSameMode(m_currentArgs); if (transformDiffers && m_currentArgs.continuedTransform()->mode() == savedMode) { m_currentArgs.restoreContinuedState(); initGuiAfterTransformMode(); slotEditingFinished(); } else { KisNodeSP root = m_transaction.rootNode() ? m_transaction.rootNode() : image()->root(); cancelStroke(); startStroke(savedMode, true); KIS_ASSERT_RECOVER_NOOP(!m_currentArgs.continuedTransform()); } } else { initTransformMode(m_currentArgs.mode()); slotEditingFinished(); } } void KisToolTransform::slotRestartTransform() { if (!m_strokeId) return; KisNodeSP root = m_transaction.rootNode(); KIS_ASSERT_RECOVER_RETURN(root); // the stroke is guaranteed to be started by an 'if' above ToolTransformArgs savedArgs(m_currentArgs); cancelStroke(); startStroke(savedArgs.mode(), true); } void KisToolTransform::slotEditingFinished() { commitChanges(); } void KisToolTransform::slotUpdateToWarpType() { setTransformMode(KisToolTransform::TransformToolMode::WarpTransformMode); } void KisToolTransform::slotUpdateToPerspectiveType() { setTransformMode(KisToolTransform::TransformToolMode::PerspectiveTransformMode); } void KisToolTransform::slotUpdateToFreeTransformType() { setTransformMode(KisToolTransform::TransformToolMode::FreeTransformMode); } void KisToolTransform::slotUpdateToLiquifyType() { setTransformMode(KisToolTransform::TransformToolMode::LiquifyTransformMode); } void KisToolTransform::slotUpdateToCageType() { setTransformMode(KisToolTransform::TransformToolMode::CageTransformMode); } void KisToolTransform::setShearY(double shear) { m_optionsWidget->slotSetShearY(shear); } void KisToolTransform::setShearX(double shear) { m_optionsWidget->slotSetShearX(shear); } void KisToolTransform::setScaleY(double scale) { m_optionsWidget->slotSetScaleY(scale); } void KisToolTransform::setScaleX(double scale) { m_optionsWidget->slotSetScaleX(scale); } void KisToolTransform::setTranslateY(double translation) { m_optionsWidget->slotSetTranslateY(translation); } void KisToolTransform::setTranslateX(double translation) { m_optionsWidget->slotSetTranslateX(translation); }