diff --git a/libs/ui/KisReferenceImage.cpp b/libs/ui/KisReferenceImage.cpp index 5111bcff56..8dbc57a99a 100644 --- a/libs/ui/KisReferenceImage.cpp +++ b/libs/ui/KisReferenceImage.cpp @@ -1,334 +1,363 @@ /* * Copyright (C) 2017 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KisReferenceImage.h" #include #include #include +#include +#include #include #include #include #include #include #include #include #include #include #include struct KisReferenceImage::Private { // Filename within .kra (for embedding) QString internalFilename; // File on disk (for linking) QString externalFilename; QImage image; QImage cachedImage; KisQImagePyramid mipmap; qreal saturation{1.0}; int id{-1}; bool embed{true}; bool loadFromFile() { KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!externalFilename.isEmpty(), false); return image.load(externalFilename); } + bool loadFromClipboard() { + image = QApplication::clipboard()->image(); + return !image.isNull(); + } + void updateCache() { if (saturation < 1.0) { cachedImage = KritaUtils::convertQImageToGrayA(image); if (saturation > 0.0) { QPainter gc2(&cachedImage); gc2.setOpacity(saturation); gc2.drawImage(QPoint(), image); } } else { cachedImage = image; } mipmap = KisQImagePyramid(cachedImage); } }; KisReferenceImage::SetSaturationCommand::SetSaturationCommand(const QList &shapes, qreal newSaturation, KUndo2Command *parent) : KUndo2Command(kundo2_i18n("Set saturation"), parent) , newSaturation(newSaturation) { images.reserve(shapes.count()); Q_FOREACH(auto *shape, shapes) { auto *reference = dynamic_cast(shape); KIS_SAFE_ASSERT_RECOVER_BREAK(reference); images.append(reference); } Q_FOREACH(auto *image, images) { oldSaturations.append(image->saturation()); } } void KisReferenceImage::SetSaturationCommand::undo() { auto saturationIterator = oldSaturations.begin(); Q_FOREACH(auto *image, images) { image->setSaturation(*saturationIterator); image->update(); saturationIterator++; } } void KisReferenceImage::SetSaturationCommand::redo() { Q_FOREACH(auto *image, images) { image->setSaturation(newSaturation); image->update(); } } KisReferenceImage::KisReferenceImage() : d(new Private()) { setKeepAspectRatio(true); } KisReferenceImage::KisReferenceImage(const KisReferenceImage &rhs) : KoTosContainer(new KoTosContainerPrivate(*rhs.d_func(), this)) , d(new Private(*rhs.d)) {} KisReferenceImage::~KisReferenceImage() {} KisReferenceImage * KisReferenceImage::fromFile(const QString &filename, const KisCoordinatesConverter &converter, QWidget *parent) { KisReferenceImage *reference = new KisReferenceImage(); reference->d->externalFilename = filename; bool ok = reference->d->loadFromFile(); if (ok) { QRect r = QRect(QPoint(), reference->d->image.size()); QSizeF shapeSize = converter.imageToDocument(r).size(); reference->setSize(shapeSize); } else { delete reference; if (parent) { QMessageBox::critical(parent, i18nc("@title:window", "Krita"), i18n("Could not load %1.", filename)); } return nullptr; } return reference; } +KisReferenceImage* KisReferenceImage::fromClipboard(const KisCoordinatesConverter &converter, QWidget *parent) +{ + KisReferenceImage *reference = new KisReferenceImage(); + bool ok = reference->d->loadFromClipboard(); + + if(ok){ + QRect r = QRect(QPoint(), reference->d->image.size()); + QSizeF size = converter.imageToDocument(r).size(); + reference->setSize(size); + } else { + delete reference; + + if(parent){ + QMessageBox::critical(parent, i18nc("@title:window", "Krita"), i18n("Could not load image from clipboard.")); + } + + return nullptr; + } + + return reference; +} + void KisReferenceImage::paint(QPainter &gc, const KoViewConverter &converter, KoShapePaintingContext &/*paintcontext*/) { if (!parent()) return; gc.save(); applyConversion(gc, converter); QSizeF shapeSize = size(); QTransform transform = QTransform::fromScale(shapeSize.width() / d->image.width(), shapeSize.height() / d->image.height()); if (d->cachedImage.isNull()) { d->updateCache(); } qreal scale; QImage prescaled = d->mipmap.getClosest(gc.transform() * transform, &scale); transform.scale(1.0 / scale, 1.0 / scale); gc.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); gc.setClipRect(QRectF(QPointF(), shapeSize), Qt::IntersectClip); gc.setTransform(transform, true); gc.drawImage(QPoint(), prescaled); gc.restore(); } void KisReferenceImage::setSaturation(qreal saturation) { d->saturation = saturation; d->cachedImage = QImage(); } qreal KisReferenceImage::saturation() const { return d->saturation; } void KisReferenceImage::setEmbed(bool embed) { KIS_SAFE_ASSERT_RECOVER_RETURN(embed || !d->externalFilename.isEmpty()); d->embed = embed; } bool KisReferenceImage::embed() { return d->embed; } bool KisReferenceImage::hasLocalFile() { return !d->externalFilename.isEmpty(); } QString KisReferenceImage::filename() const { return d->externalFilename; } QString KisReferenceImage::internalFile() const { return d->internalFilename; } void KisReferenceImage::setFilename(const QString &filename) { d->externalFilename = filename; d->embed = false; } QColor KisReferenceImage::getPixel(QPointF position) { if (transparency() == 1.0) return Qt::transparent; const QSizeF shapeSize = size(); const QTransform scale = QTransform::fromScale(d->image.width() / shapeSize.width(), d->image.height() / shapeSize.height()); const QTransform transform = absoluteTransformation(nullptr).inverted() * scale; const QPointF localPosition = position * transform; if (d->cachedImage.isNull()) { d->updateCache(); } return d->cachedImage.pixelColor(localPosition.toPoint()); } void KisReferenceImage::saveXml(QDomDocument &document, QDomElement &parentElement, int id) { d->id = id; QDomElement element = document.createElement("referenceimage"); if (d->embed) { d->internalFilename = QString("reference_images/%1.png").arg(id); } const QString src = d->embed ? d->internalFilename : (QString("file://") + d->externalFilename); element.setAttribute("src", src); const QSizeF &shapeSize = size(); element.setAttribute("width", KisDomUtils::toString(shapeSize.width())); element.setAttribute("height", KisDomUtils::toString(shapeSize.height())); element.setAttribute("keepAspectRatio", keepAspectRatio() ? "true" : "false"); element.setAttribute("transform", SvgUtil::transformToString(transform())); element.setAttribute("opacity", KisDomUtils::toString(1.0 - transparency())); element.setAttribute("saturation", KisDomUtils::toString(d->saturation)); parentElement.appendChild(element); } KisReferenceImage * KisReferenceImage::fromXml(const QDomElement &elem) { auto *reference = new KisReferenceImage(); const QString &src = elem.attribute("src"); if (src.startsWith("file://")) { reference->d->externalFilename = src.mid(7); reference->d->embed = false; } else { reference->d->internalFilename = src; reference->d->embed = true; } qreal width = KisDomUtils::toDouble(elem.attribute("width", "100")); qreal height = KisDomUtils::toDouble(elem.attribute("height", "100")); reference->setSize(QSizeF(width, height)); reference->setKeepAspectRatio(elem.attribute("keepAspectRatio", "true").toLower() == "true"); auto transform = SvgTransformParser(elem.attribute("transform")).transform(); reference->setTransformation(transform); qreal opacity = KisDomUtils::toDouble(elem.attribute("opacity", "1")); reference->setTransparency(1.0 - opacity); qreal saturation = KisDomUtils::toDouble(elem.attribute("opacity", "1")); reference->setSaturation(saturation); return reference; } bool KisReferenceImage::saveImage(KoStore *store) const { if (!d->embed) return true; if (!store->open(d->internalFilename)) { return false; } bool saved = false; KoStoreDevice storeDev(store); if (storeDev.open(QIODevice::WriteOnly)) { saved = d->image.save(&storeDev, "PNG"); } return store->close() && saved; } bool KisReferenceImage::loadImage(KoStore *store) { if (!d->embed) { return d->loadFromFile(); } if (!store->open(d->internalFilename)) { return false; } KoStoreDevice storeDev(store); if (!storeDev.open(QIODevice::ReadOnly)) { return false; } if (!d->image.load(&storeDev, "PNG")) { return false; } return store->close(); } KoShape *KisReferenceImage::cloneShape() const { return new KisReferenceImage(*this); } diff --git a/libs/ui/KisReferenceImage.h b/libs/ui/KisReferenceImage.h index 4e7193acaf..16c39174e6 100644 --- a/libs/ui/KisReferenceImage.h +++ b/libs/ui/KisReferenceImage.h @@ -1,96 +1,97 @@ /* * Copyright (C) 2017 Boudewijn Rempt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KISREFERENCEIMAGE_H #define KISREFERENCEIMAGE_H #include #include #include #include #include class QImage; class QPointF; class QPainter; class QRectF; class KoStore; class KisCoordinatesConverter; class KisCanvas2; /** * @brief The KisReferenceImage class represents a single reference image */ class KRITAUI_EXPORT KisReferenceImage : public KoTosContainer { public: struct KRITAUI_EXPORT SetSaturationCommand : public KUndo2Command { QVector images; QVector oldSaturations; qreal newSaturation; explicit SetSaturationCommand(const QList &images, qreal newSaturation, KUndo2Command *parent = 0); void undo() override; void redo() override; }; KisReferenceImage(); KisReferenceImage(const KisReferenceImage &rhs); ~KisReferenceImage(); KoShape *cloneShape() const override; /** * Load a reference image from specified file. * If parent is provided and the image cannot be loaded, a warning message will be displayed to user. * @return reference image or null if one could not be loaded */ static KisReferenceImage * fromFile(const QString &filename, const KisCoordinatesConverter &converter, QWidget *parent /*= nullptr*/); + static KisReferenceImage * fromClipboard(const KisCoordinatesConverter &converter, QWidget *parent); void setSaturation(qreal saturation); qreal saturation() const; void setEmbed(bool embed); bool embed(); bool hasLocalFile(); void setFilename(const QString &filename); QString filename() const; QString internalFile() const; void paint(QPainter &gc, const KoViewConverter &converter, KoShapePaintingContext &paintcontext) override; bool loadOdf(const KoXmlElement &/*element*/, KoShapeLoadingContext &/*context*/) override { return false; } void saveOdf(KoShapeSavingContext &/*context*/) const override {} QColor getPixel(QPointF position); void saveXml(QDomDocument &document, QDomElement &parentElement, int id); bool saveImage(KoStore *store) const; static KisReferenceImage * fromXml(const QDomElement &elem); bool loadImage(KoStore *store); private: struct Private; const QScopedPointer d; }; #endif // KISREFERENCEIMAGE_H diff --git a/plugins/tools/defaulttool/referenceimagestool/ToolReferenceImages.cpp b/plugins/tools/defaulttool/referenceimagestool/ToolReferenceImages.cpp index afe9d5a844..677f7df9d7 100644 --- a/plugins/tools/defaulttool/referenceimagestool/ToolReferenceImages.cpp +++ b/plugins/tools/defaulttool/referenceimagestool/ToolReferenceImages.cpp @@ -1,289 +1,303 @@ /* * Copyright (c) 2017 Boudewijn Rempt * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ToolReferenceImages.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ToolReferenceImagesWidget.h" #include "KisReferenceImageCollection.h" ToolReferenceImages::ToolReferenceImages(KoCanvasBase * canvas) : DefaultTool(canvas, false) { setObjectName("ToolReferenceImages"); } ToolReferenceImages::~ToolReferenceImages() { } void ToolReferenceImages::activate(ToolActivation toolActivation, const QSet &shapes) { DefaultTool::activate(toolActivation, shapes); auto kisCanvas = dynamic_cast(canvas()); connect(kisCanvas->image(), SIGNAL(sigNodeAddedAsync(KisNodeSP)), this, SLOT(slotNodeAdded(KisNodeSP))); auto referenceImageLayer = document()->referenceImagesLayer(); if (referenceImageLayer) { setReferenceImageLayer(referenceImageLayer); } } void ToolReferenceImages::deactivate() { DefaultTool::deactivate(); } void ToolReferenceImages::slotNodeAdded(KisNodeSP node) { auto *referenceImagesLayer = dynamic_cast(node.data()); if (referenceImagesLayer) { setReferenceImageLayer(referenceImagesLayer); } } void ToolReferenceImages::setReferenceImageLayer(KisSharedPtr layer) { m_layer = layer; connect(layer.data(), SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged())); } void ToolReferenceImages::addReferenceImage() { auto kisCanvas = dynamic_cast(canvas()); KIS_ASSERT_RECOVER_RETURN(kisCanvas) KoFileDialog dialog(kisCanvas->viewManager()->mainWindow(), KoFileDialog::OpenFile, "OpenReferenceImage"); dialog.setCaption(i18n("Select a Reference Image")); QStringList locations = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation); if (!locations.isEmpty()) { dialog.setDefaultDir(locations.first()); } QString filename = dialog.filename(); if (filename.isEmpty()) return; if (!QFileInfo(filename).exists()) return; auto *reference = KisReferenceImage::fromFile(filename, *kisCanvas->coordinatesConverter(), canvas()->canvasWidget()); if (reference) { KisDocument *doc = document(); doc->addCommand(KisReferenceImagesLayer::addReferenceImages(doc, {reference})); } } +void ToolReferenceImages::pasteReferenceImage() +{ + KisCanvas2* kisCanvas = dynamic_cast(canvas()); + KIS_ASSERT_RECOVER_RETURN(kisCanvas) + + KisReferenceImage* reference = KisReferenceImage::fromClipboard(*kisCanvas->coordinatesConverter(), canvas()->canvasWidget()); + if(reference) { + KisDocument *doc = document(); + doc->addCommand(KisReferenceImagesLayer::addReferenceImages(doc, {reference})); + } +} + + + void ToolReferenceImages::removeAllReferenceImages() { auto layer = m_layer.toStrongRef(); if (!layer) return; canvas()->addCommand(layer->removeReferenceImages(document(), layer->shapes())); } void ToolReferenceImages::loadReferenceImages() { auto kisCanvas = dynamic_cast(canvas()); KIS_ASSERT_RECOVER_RETURN(kisCanvas) KoFileDialog dialog(kisCanvas->viewManager()->mainWindow(), KoFileDialog::OpenFile, "OpenReferenceImageCollection"); dialog.setMimeTypeFilters(QStringList() << "application/x-krita-reference-images"); dialog.setCaption(i18n("Load Reference Images")); QStringList locations = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation); if (!locations.isEmpty()) { dialog.setDefaultDir(locations.first()); } QString filename = dialog.filename(); if (filename.isEmpty()) return; if (!QFileInfo(filename).exists()) return; QFile file(filename); if (!file.open(QIODevice::ReadOnly)) { QMessageBox::critical(nullptr, i18nc("@title:window", "Krita"), i18n("Could not open '%1'.", filename)); return; } KisReferenceImageCollection collection; if (collection.load(&file)) { QList shapes; Q_FOREACH(auto *reference, collection.referenceImages()) { shapes.append(reference); } KisDocument *doc = document(); doc->addCommand(KisReferenceImagesLayer::addReferenceImages(doc, shapes)); } else { QMessageBox::critical(nullptr, i18nc("@title:window", "Krita"), i18n("Could not load reference images from '%1'.", filename)); } file.close(); } void ToolReferenceImages::saveReferenceImages() { auto layer = m_layer.toStrongRef(); if (!layer || layer->shapeCount() == 0) return; auto kisCanvas = dynamic_cast(canvas()); KIS_ASSERT_RECOVER_RETURN(kisCanvas) KoFileDialog dialog(kisCanvas->viewManager()->mainWindow(), KoFileDialog::SaveFile, "SaveReferenceImageCollection"); dialog.setMimeTypeFilters(QStringList() << "application/x-krita-reference-images"); dialog.setCaption(i18n("Save Reference Images")); QStringList locations = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation); if (!locations.isEmpty()) { dialog.setDefaultDir(locations.first()); } QString filename = dialog.filename(); if (filename.isEmpty()) return; QFile file(filename); if (!file.open(QIODevice::WriteOnly)) { QMessageBox::critical(nullptr, i18nc("@title:window", "Krita"), i18n("Could not open '%1' for saving.", filename)); return; } KisReferenceImageCollection collection(layer->referenceImages()); bool ok = collection.save(&file); file.close(); if (!ok) { QMessageBox::critical(nullptr, i18nc("@title:window", "Krita"), i18n("Failed to save reference images.")); } } void ToolReferenceImages::slotSelectionChanged() { auto layer = m_layer.toStrongRef(); if (!layer) return; m_optionsWidget->selectionChanged(layer->shapeManager()->selection()); updateActions(); } QList> ToolReferenceImages::createOptionWidgets() { // Instead of inheriting DefaultTool's multi-tab implementation, inherit straight from KoToolBase return KoToolBase::createOptionWidgets(); } QWidget *ToolReferenceImages::createOptionWidget() { if (!m_optionsWidget) { m_optionsWidget = new ToolReferenceImagesWidget(this); // 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); } return m_optionsWidget; } bool ToolReferenceImages::isValidForCurrentLayer() const { return true; } KoShapeManager *ToolReferenceImages::shapeManager() const { auto layer = m_layer.toStrongRef(); return layer ? layer->shapeManager() : nullptr; } KoSelection *ToolReferenceImages::koSelection() const { auto manager = shapeManager(); return manager ? manager->selection() : nullptr; } void ToolReferenceImages::updateDistinctiveActions(const QList &) { action("object_group")->setEnabled(false); action("object_unite")->setEnabled(false); action("object_intersect")->setEnabled(false); action("object_subtract")->setEnabled(false); action("object_split")->setEnabled(false); action("object_ungroup")->setEnabled(false); } void ToolReferenceImages::deleteSelection() { auto layer = m_layer.toStrongRef(); if (!layer) return; QList shapes = koSelection()->selectedShapes(); if (!shapes.empty()) { canvas()->addCommand(layer->removeReferenceImages(document(), shapes)); } } KisDocument *ToolReferenceImages::document() const { auto kisCanvas = dynamic_cast(canvas()); return kisCanvas->imageView()->document(); } QList ToolReferenceImagesFactory::createActionsImpl() { KisActionRegistry *actionRegistry = KisActionRegistry::instance(); QList actions = DefaultToolFactory::createActionsImpl(); actions << actionRegistry->makeQAction("object_order_front"); actions << actionRegistry->makeQAction("object_order_raise"); actions << actionRegistry->makeQAction("object_order_lower"); actions << actionRegistry->makeQAction("object_order_back"); actions << actionRegistry->makeQAction("object_group"); actions << actionRegistry->makeQAction("object_ungroup"); actions << actionRegistry->makeQAction("object_transform_rotate_90_cw"); actions << actionRegistry->makeQAction("object_transform_rotate_90_ccw"); actions << actionRegistry->makeQAction("object_transform_rotate_180"); actions << actionRegistry->makeQAction("object_transform_mirror_horizontally"); actions << actionRegistry->makeQAction("object_transform_mirror_vertically"); actions << actionRegistry->makeQAction("object_transform_reset"); actions << actionRegistry->makeQAction("object_unite"); actions << actionRegistry->makeQAction("object_intersect"); actions << actionRegistry->makeQAction("object_subtract"); actions << actionRegistry->makeQAction("object_split"); return actions; } diff --git a/plugins/tools/defaulttool/referenceimagestool/ToolReferenceImages.h b/plugins/tools/defaulttool/referenceimagestool/ToolReferenceImages.h index 33adb33ece..02d4a3c327 100644 --- a/plugins/tools/defaulttool/referenceimagestool/ToolReferenceImages.h +++ b/plugins/tools/defaulttool/referenceimagestool/ToolReferenceImages.h @@ -1,110 +1,111 @@ /* * Copyright (c) 2017 Boudewijn Rempt * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef TOOL_REFERENCE_IMAGES_H #define TOOL_REFERENCE_IMAGES_H #include #include #include #include #include "kis_painting_assistant.h" #include #include #include #include class ToolReferenceImagesWidget; class KisReferenceImagesLayer; class ToolReferenceImages : public DefaultTool { Q_OBJECT public: ToolReferenceImages(KoCanvasBase * canvas); ~ToolReferenceImages() override; virtual quint32 priority() { return 3; } void mouseDoubleClickEvent(KoPointerEvent */*event*/) override {} void deleteSelection() override; protected: QList> createOptionWidgets() override; QWidget *createOptionWidget() override; bool isValidForCurrentLayer() const override; KoShapeManager *shapeManager() const override; KoSelection *koSelection() const override; void updateDistinctiveActions(const QList &editableShapes) override; public Q_SLOTS: void activate(ToolActivation toolActivation, const QSet &shapes) override; void deactivate() override; void addReferenceImage(); + void pasteReferenceImage(); void removeAllReferenceImages(); void saveReferenceImages(); void loadReferenceImages(); void slotNodeAdded(KisNodeSP node); void slotSelectionChanged(); private: friend class ToolReferenceImagesWidget; ToolReferenceImagesWidget *m_optionsWidget = nullptr; KisWeakSharedPtr m_layer; KisDocument *document() const; void setReferenceImageLayer(KisSharedPtr layer); }; class ToolReferenceImagesFactory : public DefaultToolFactory { public: ToolReferenceImagesFactory() : DefaultToolFactory("ToolReferenceImages") { setToolTip(i18n("Reference Images Tool")); setSection(TOOL_TYPE_VIEW); setIconName(koIconNameCStr("krita_tool_reference_images")); setPriority(2); setActivationShapeId(KRITA_TOOL_ACTIVATION_ID); }; ~ToolReferenceImagesFactory() override {} KoToolBase * createTool(KoCanvasBase * canvas) override { return new ToolReferenceImages(canvas); } QList createActionsImpl() override; }; #endif diff --git a/plugins/tools/defaulttool/referenceimagestool/ToolReferenceImagesWidget.cpp b/plugins/tools/defaulttool/referenceimagestool/ToolReferenceImagesWidget.cpp index efa2de987c..31e9abb2d6 100644 --- a/plugins/tools/defaulttool/referenceimagestool/ToolReferenceImagesWidget.cpp +++ b/plugins/tools/defaulttool/referenceimagestool/ToolReferenceImagesWidget.cpp @@ -1,213 +1,250 @@ /* * Copyright (c) 2017 Eugene Ingerman * * 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 "ToolReferenceImagesWidget.h" #include "ui_WdgToolOptions.h" #include #include #include #include #include #include +#include +#include +#include + #include "ToolReferenceImages.h" struct ToolReferenceImagesWidget::Private { Private(ToolReferenceImages *tool) : tool(tool) { } Ui_WdgToolOptions *ui; ToolReferenceImages *tool; }; ToolReferenceImagesWidget::ToolReferenceImagesWidget(ToolReferenceImages *tool, KisCanvasResourceProvider */*provider*/, QWidget *parent) : QWidget(parent), d(new Private(tool)) { d->ui = new Ui_WdgToolOptions(); d->ui->setupUi(this); d->ui->opacitySlider->setRange(0, 100); d->ui->opacitySlider->setPrefixes(i18n("Opacity: "), i18n("Opacity [*varies*]: ")); d->ui->opacitySlider->setSuffix(i18n(" %")); d->ui->opacitySlider->setValueGetter( [](KoShape *s){ return 100.0 * (1.0 - s->transparency()); } ); d->ui->saturationSlider->setRange(0, 100); d->ui->saturationSlider->setPrefixes(i18n("Saturation: "), i18n("Saturation [*varies*]: ")); d->ui->saturationSlider->setSuffix(i18n(" %")); d->ui->saturationSlider->setValueGetter( [](KoShape *s){ auto *r = dynamic_cast(s); KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(r, 0.0); return 100.0 * r->saturation(); } ); d->ui->bnAddReferenceImage->setToolTip(i18n("Add Reference Image")); d->ui->bnAddReferenceImage->setIcon(KisIconUtils::loadIcon("addlayer")); d->ui->bnDelete->setToolTip(i18n("Delete all Reference Images")); d->ui->bnDelete->setIcon(KisIconUtils::loadIcon("edit-clear")); d->ui->bnLoad->setToolTip(i18n("Load Reference Images Set")); d->ui->bnLoad->setIcon(KisIconUtils::loadIcon("document-open")); d->ui->bnSave->setToolTip(i18n("Export Reference Images Set")); d->ui->bnSave->setIcon(KisIconUtils::loadIcon("document-save")); - + d->ui->bnPasteReferenceImage->setEnabled(!QApplication::clipboard()->image().isNull()); connect(d->ui->bnAddReferenceImage, SIGNAL(clicked()), tool, SLOT(addReferenceImage())); + connect(d->ui->bnPasteReferenceImage, SIGNAL(clicked()), tool, SLOT(pasteReferenceImage())); + connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(slotCheckClipboardContents())); + connect(d->ui->bnDelete, SIGNAL(clicked()), tool, SLOT(removeAllReferenceImages())); connect(d->ui->bnSave, SIGNAL(clicked()), tool, SLOT(saveReferenceImages())); connect(d->ui->bnLoad, SIGNAL(clicked()), tool, SLOT(loadReferenceImages())); connect(d->ui->chkKeepAspectRatio, SIGNAL(stateChanged(int)), this, SLOT(slotKeepAspectChanged())); connect(d->ui->opacitySlider, SIGNAL(valueChanged(qreal)), this, SLOT(slotOpacitySliderChanged(qreal))); connect(d->ui->saturationSlider, SIGNAL(valueChanged(qreal)), this, SLOT(slotSaturationSliderChanged(qreal))); d->ui->referenceImageLocationCombobox->addItem(i18n("Embed to .KRA")); d->ui->referenceImageLocationCombobox->addItem(i18n("Link to Image")); connect(d->ui->referenceImageLocationCombobox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotSaveLocationChanged(int))); updateVisibility(false); // no selection when we start } ToolReferenceImagesWidget::~ToolReferenceImagesWidget() { } void ToolReferenceImagesWidget::selectionChanged(KoSelection *selection) { QList shapes = selection->selectedEditableShapes(); d->ui->opacitySlider->setSelection(shapes); d->ui->saturationSlider->setSelection(shapes); bool anyKeepingAspectRatio = false; bool anyNotKeepingAspectRatio = false; bool anyEmbedded = false; bool anyLinked = false; bool anyNonLinkable = false; bool anySelected = selection->count() > 0; Q_FOREACH(KoShape *shape, shapes) { KisReferenceImage *reference = dynamic_cast(shape); anyKeepingAspectRatio |= shape->keepAspectRatio(); anyNotKeepingAspectRatio |= !shape->keepAspectRatio(); if (reference) { anyEmbedded |= reference->embed(); anyLinked |= !reference->embed(); anyNonLinkable |= !reference->hasLocalFile(); } } KisSignalsBlocker blocker( d->ui->chkKeepAspectRatio, d->ui->referenceImageLocationCombobox ); d->ui->chkKeepAspectRatio->setCheckState( (anyKeepingAspectRatio && anyNotKeepingAspectRatio) ? Qt::PartiallyChecked : anyKeepingAspectRatio ? Qt::Checked : Qt::Unchecked); // set save location combobox bool imagesEmbedded = anyEmbedded && !anyLinked; int comboBoxIndex = imagesEmbedded ? 0 : 1; // maps state to combobox index d->ui->referenceImageLocationCombobox->setCurrentIndex(comboBoxIndex); updateVisibility(anySelected); } +void ToolReferenceImagesWidget::slotCheckClipboardContents() { + d->ui->bnPasteReferenceImage->setEnabled(!QApplication::clipboard()->image().isNull()); +} + void ToolReferenceImagesWidget::slotKeepAspectChanged() { KoSelection *selection = d->tool->koSelection(); QList shapes = selection->selectedEditableShapes(); KUndo2Command *cmd = new KoShapeKeepAspectRatioCommand(shapes, d->ui->chkKeepAspectRatio->isChecked()); d->tool->canvas()->addCommand(cmd); } void ToolReferenceImagesWidget::slotOpacitySliderChanged(qreal newOpacity) { QList shapes = d->ui->opacitySlider->selection(); if (shapes.isEmpty()) return; KUndo2Command *cmd = new KoShapeTransparencyCommand(shapes, 1.0 - newOpacity / 100.0); d->tool->canvas()->addCommand(cmd); } void ToolReferenceImagesWidget::slotSaturationSliderChanged(qreal newSaturation) { QList shapes = d->ui->saturationSlider->selection(); if (shapes.isEmpty()) return; KUndo2Command *cmd = new KisReferenceImage::SetSaturationCommand(shapes, newSaturation / 100.0); d->tool->canvas()->addCommand(cmd); } void ToolReferenceImagesWidget::slotSaveLocationChanged(int index) { KoSelection *selection = d->tool->koSelection(); QList shapes = selection->selectedEditableShapes(); Q_FOREACH(KoShape *shape, shapes) { KisReferenceImage *reference = dynamic_cast(shape); KIS_SAFE_ASSERT_RECOVER_RETURN(reference); if (index == 0) { // embed to KRA reference->setEmbed(true); } else { // link to file - reference->setEmbed(false); + if (reference->hasLocalFile()) { + reference->setEmbed(false); + } else { + //In the case no local file is found, switch back to embed file data. + d->ui->referenceImageLocationCombobox->setCurrentIndex(0); + } } } } void ToolReferenceImagesWidget::updateVisibility(bool hasSelection) { // hide UI elements if nothing is selected. d->ui->referenceImageLocationCombobox->setVisible(hasSelection); d->ui->chkKeepAspectRatio->setVisible(hasSelection); d->ui->saveLocationLabel->setVisible(hasSelection); d->ui->opacitySlider->setVisible(hasSelection); d->ui->saturationSlider->setVisible(hasSelection); // show a label indicating that a selection is required to show options d->ui->referenceImageOptionsLabel->setVisible(!hasSelection); + if (hasSelection) { + KoSelection* selection = d->tool->koSelection(); + QList shapes = selection->selectedEditableShapes(); + bool usesLocalFile = true; + + Q_FOREACH(KoShape *shape, shapes) { + KisReferenceImage *reference = dynamic_cast(shape); + + if (reference) { + usesLocalFile &= reference->hasLocalFile(); + } + } + + QStandardItemModel* model = dynamic_cast(d->ui->referenceImageLocationCombobox->model()); + + if (model) { + QStandardItem* item = model->item(1); + item->setFlags(usesLocalFile ? item->flags() | Qt::ItemIsEnabled : + item->flags() & ~Qt::ItemIsEnabled); + } + } } diff --git a/plugins/tools/defaulttool/referenceimagestool/ToolReferenceImagesWidget.h b/plugins/tools/defaulttool/referenceimagestool/ToolReferenceImagesWidget.h index a5cb030541..a8b249e477 100644 --- a/plugins/tools/defaulttool/referenceimagestool/ToolReferenceImagesWidget.h +++ b/plugins/tools/defaulttool/referenceimagestool/ToolReferenceImagesWidget.h @@ -1,56 +1,56 @@ /* * Copyright (c) 2017 Eugene Ingerman * * 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 __TOOL_REFERENCE_IMAGES_WIDGET_H #define __TOOL_REFERENCE_IMAGES_WIDGET_H #include #include #include #include "kis_types.h" class KoColor; class KoSelection; class KisCanvasResourceProvider; class ToolReferenceImages; class ToolReferenceImagesWidget : public QWidget { Q_OBJECT public: ToolReferenceImagesWidget(ToolReferenceImages *tool, KisCanvasResourceProvider *provider = 0, QWidget *parent = 0); ~ToolReferenceImagesWidget() override; void selectionChanged(KoSelection *selection); + private Q_SLOTS: void slotOpacitySliderChanged(qreal); void slotSaturationSliderChanged(qreal); void slotKeepAspectChanged(); void slotSaveLocationChanged(int index); - - + void slotCheckClipboardContents(); private: struct Private; const QScopedPointer d; void updateVisibility(bool hasSelection); }; #endif diff --git a/plugins/tools/defaulttool/referenceimagestool/WdgToolOptions.ui b/plugins/tools/defaulttool/referenceimagestool/WdgToolOptions.ui index f7bd0dbf77..37af1f41ac 100644 --- a/plugins/tools/defaulttool/referenceimagestool/WdgToolOptions.ui +++ b/plugins/tools/defaulttool/referenceimagestool/WdgToolOptions.ui @@ -1,208 +1,231 @@ WdgToolOptions 0 0 - 279 + 288 352 0 0 6 0 Keep aspect ratio Save Location: Add/Select an image to show options true Qt::Vertical QSizePolicy::MinimumExpanding 20 20 Qt::Horizontal 0 0 0 18 18 true + + + + Paste Reference Image From System Clipboard + + + + + + + .. + + + false + + + false + + + true + + + Qt::Horizontal 20 20 0 0 18 18 true 0 0 18 18 true 0 0 0 0 All 18 18 true KisShapePropertySlider QWidget
KisSelectionPropertySlider.h
1