1 /*
2 * Copyright (C) 2017 Jouni Pentikäinen <joupent@gmail.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #include <KoShapeCreateCommand.h>
21 #include <KoShapeDeleteCommand.h>
22 #include <KoKeepShapesSelectedCommand.h>
23 #include <KoSelection.h>
24 #include <kis_node_visitor.h>
25 #include <kis_processing_visitor.h>
26 #include <kis_shape_layer_canvas.h>
27
28 #include "KisReferenceImagesLayer.h"
29 #include "KisReferenceImage.h"
30 #include "KisDocument.h"
31
32 struct AddReferenceImagesCommand : KoShapeCreateCommand
33 {
AddReferenceImagesCommandAddReferenceImagesCommand34 AddReferenceImagesCommand(KisDocument *document, KisSharedPtr<KisReferenceImagesLayer> layer, const QList<KoShape*> referenceImages, KUndo2Command *parent = nullptr)
35 : KoShapeCreateCommand(layer->shapeController(), referenceImages, layer.data(), parent, kundo2_i18n("Add reference image"))
36 , m_document(document)
37 , m_layer(layer)
38 {}
39
redoAddReferenceImagesCommand40 void redo() override {
41 auto layer = m_document->referenceImagesLayer();
42 KIS_SAFE_ASSERT_RECOVER_NOOP(!layer || layer == m_layer);
43
44 if (!layer) {
45 m_document->setReferenceImagesLayer(m_layer, true);
46 }
47
48 KoShapeCreateCommand::redo();
49 }
50
undoAddReferenceImagesCommand51 void undo() override {
52 KoShapeCreateCommand::undo();
53
54 if (m_layer->shapeCount() == 0) {
55 m_document->setReferenceImagesLayer(nullptr, true);
56 }
57 }
58
59 private:
60 KisDocument *m_document;
61 KisSharedPtr<KisReferenceImagesLayer> m_layer;
62 };
63
64 struct RemoveReferenceImagesCommand : KoShapeDeleteCommand
65 {
RemoveReferenceImagesCommandRemoveReferenceImagesCommand66 RemoveReferenceImagesCommand(KisDocument *document, KisSharedPtr<KisReferenceImagesLayer> layer, QList<KoShape *> referenceImages, KUndo2Command *parent = nullptr)
67 : KoShapeDeleteCommand(layer->shapeController(), referenceImages, parent)
68 , m_document(document)
69 , m_layer(layer)
70 {}
71
72
redoRemoveReferenceImagesCommand73 void redo() override {
74 KoShapeDeleteCommand::redo();
75
76 if (m_layer->shapeCount() == 0) {
77 m_document->setReferenceImagesLayer(nullptr, true);
78 }
79 }
80
undoRemoveReferenceImagesCommand81 void undo() override {
82 auto layer = m_document->referenceImagesLayer();
83 KIS_SAFE_ASSERT_RECOVER_NOOP(!layer || layer == m_layer);
84
85 if (!layer) {
86 m_document->setReferenceImagesLayer(m_layer, true);
87 }
88
89 KoShapeDeleteCommand::undo();
90 }
91
92 private:
93 KisDocument *m_document;
94 KisSharedPtr<KisReferenceImagesLayer> m_layer;
95 };
96
97 class ReferenceImagesCanvas : public KisShapeLayerCanvasBase
98 {
99 public:
ReferenceImagesCanvas(KisReferenceImagesLayer * parent,KisImageWSP image)100 ReferenceImagesCanvas(KisReferenceImagesLayer *parent, KisImageWSP image)
101 : KisShapeLayerCanvasBase(parent, image)
102 , m_layer(parent)
103 {}
104
updateCanvas(const QRectF & rect)105 void updateCanvas(const QRectF &rect) override
106 {
107 if (!m_layer->image() || m_isDestroying) {
108 return;
109 }
110
111 QRectF r = m_viewConverter->documentToView(rect);
112 m_layer->signalUpdate(r);
113 }
114
forceRepaint()115 void forceRepaint() override
116 {
117 m_layer->signalUpdate(m_layer->boundingImageRect());
118 }
119
hasPendingUpdates() const120 bool hasPendingUpdates() const override
121 {
122 return false;
123 }
124
rerenderAfterBeingInvisible()125 void rerenderAfterBeingInvisible() override {}
resetCache()126 void resetCache() override {}
setImage(KisImageWSP image)127 void setImage(KisImageWSP image) override
128 {
129 m_viewConverter->setImage(image);
130 }
131
132 private:
133 KisReferenceImagesLayer *m_layer;
134 };
135
KisReferenceImagesLayer(KoShapeControllerBase * shapeController,KisImageWSP image)136 KisReferenceImagesLayer::KisReferenceImagesLayer(KoShapeControllerBase* shapeController, KisImageWSP image)
137 : KisShapeLayer(shapeController, image, i18n("Reference images"), OPACITY_OPAQUE_U8, new ReferenceImagesCanvas(this, image))
138 {}
139
KisReferenceImagesLayer(const KisReferenceImagesLayer & rhs)140 KisReferenceImagesLayer::KisReferenceImagesLayer(const KisReferenceImagesLayer &rhs)
141 : KisShapeLayer(rhs, rhs.shapeController(), new ReferenceImagesCanvas(this, rhs.image()))
142 {}
143
addReferenceImages(KisDocument * document,const QList<KoShape * > referenceImages)144 KUndo2Command * KisReferenceImagesLayer::addReferenceImages(KisDocument *document, const QList<KoShape*> referenceImages)
145 {
146 KisSharedPtr<KisReferenceImagesLayer> layer = document->referenceImagesLayer();
147 if (!layer) {
148 layer = new KisReferenceImagesLayer(document->shapeController(), document->image());
149 }
150
151 KUndo2Command *parentCommand = new KUndo2Command();
152
153 new KoKeepShapesSelectedCommand(layer->shapeManager()->selection()->selectedShapes(), {}, layer->selectedShapesProxy(), KisCommandUtils::FlipFlopCommand::State::INITIALIZING, parentCommand);
154 AddReferenceImagesCommand *cmd = new AddReferenceImagesCommand(document, layer, referenceImages, parentCommand);
155 parentCommand->setText(cmd->text());
156 new KoKeepShapesSelectedCommand({}, referenceImages, layer->selectedShapesProxy(), KisCommandUtils::FlipFlopCommand::State::FINALIZING, parentCommand);
157
158 return parentCommand;
159 }
160
removeReferenceImages(KisDocument * document,QList<KoShape * > referenceImages)161 KUndo2Command * KisReferenceImagesLayer::removeReferenceImages(KisDocument *document, QList<KoShape*> referenceImages)
162 {
163 return new RemoveReferenceImagesCommand(document, this, referenceImages);
164 }
165
referenceImages() const166 QVector<KisReferenceImage*> KisReferenceImagesLayer::referenceImages() const
167 {
168 QVector<KisReferenceImage*> references;
169
170 Q_FOREACH(auto shape, shapes()) {
171 KisReferenceImage *referenceImage = dynamic_cast<KisReferenceImage*>(shape);
172 if (referenceImage) {
173 references.append(referenceImage);
174 }
175 }
176 return references;
177 }
178
paintReferences(QPainter & painter)179 void KisReferenceImagesLayer::paintReferences(QPainter &painter) {
180 painter.setTransform(converter()->documentToView(), true);
181 shapeManager()->paint(painter, false);
182 }
183
allowAsChild(KisNodeSP) const184 bool KisReferenceImagesLayer::allowAsChild(KisNodeSP) const
185 {
186 return false;
187 }
188
accept(KisNodeVisitor & visitor)189 bool KisReferenceImagesLayer::accept(KisNodeVisitor &visitor)
190 {
191 return visitor.visit(this);
192 }
193
accept(KisProcessingVisitor & visitor,KisUndoAdapter * undoAdapter)194 void KisReferenceImagesLayer::accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter)
195 {
196 visitor.visit(this, undoAdapter);
197 }
198
isFakeNode() const199 bool KisReferenceImagesLayer::isFakeNode() const
200 {
201 return true;
202 }
203
setProfile(const KoColorProfile * profile)204 KUndo2Command *KisReferenceImagesLayer::setProfile(const KoColorProfile *profile)
205 {
206 // references should not be converted with the image
207 Q_UNUSED(profile);
208 return 0;
209 }
210
convertTo(const KoColorSpace * dstColorSpace,KoColorConversionTransformation::Intent renderingIntent,KoColorConversionTransformation::ConversionFlags conversionFlags)211 KUndo2Command *KisReferenceImagesLayer::convertTo(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
212 {
213 // references should not be converted with the image
214 Q_UNUSED(dstColorSpace);
215 Q_UNUSED(renderingIntent);
216 Q_UNUSED(conversionFlags);
217 return 0;
218 }
219
signalUpdate(const QRectF & rect)220 void KisReferenceImagesLayer::signalUpdate(const QRectF &rect)
221 {
222 emit sigUpdateCanvas(rect);
223 }
224
boundingImageRect() const225 QRectF KisReferenceImagesLayer::boundingImageRect() const
226 {
227 return converter()->documentToView(boundingRect());
228 }
229
getPixel(QPointF position) const230 QColor KisReferenceImagesLayer::getPixel(QPointF position) const
231 {
232 const QPointF docPoint = converter()->viewToDocument(position);
233
234 KoShape *shape = shapeManager()->shapeAt(docPoint);
235
236 if (shape) {
237 auto *reference = dynamic_cast<KisReferenceImage*>(shape);
238 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(reference, QColor());
239
240 return reference->getPixel(docPoint);
241 }
242
243 return QColor();
244 }
245