Krita Source Code Documentation
Loading...
Searching...
No Matches
KoCanvasControllerWidgetViewport_p.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 *
3 * SPDX-FileCopyrightText: 2006-2007, 2009 Thomas Zander <zander@kde.org>
4 * SPDX-FileCopyrightText: 2006 Thorsten Zachmann <zachmann@kde.org>
5 * SPDX-FileCopyrightText: 2007-2010 Boudewijn Rempt <boud@valdyas.org>
6 *
7 * SPDX-License-Identifier: LGPL-2.0-or-later
8 */
9
11
12#include <limits.h>
13#include <stdlib.h>
14
15#include <QPainter>
16#include <QDragEnterEvent>
17#include <QMimeData>
18
19#include <KoProperties.h>
20
21#include <FlakeDebug.h>
22
23#include "KoShape.h"
24#include "KoShape_p.h"
25#include "KoShapeFactoryBase.h" // for the SHAPE mimetypes
26#include "KoShapeRegistry.h"
27#include "KoShapeController.h"
28#include "KoShapeManager.h"
29#include "KoSelection.h"
30#include "KoCanvasBase.h"
31#include "KoShapeLayer.h"
32#include "KoToolProxy.h"
34#include "KoViewConverter.h"
35#include "KoSvgPaste.h"
36#include <kis_canvas2.h>
37
38// ********** Viewport **********
40 : QWidget(parent)
41 , m_draggedShape(0)
42 , m_canvas(0)
43{
44 setAutoFillBackground(true);
45 setAcceptDrops(true);
46 setMouseTracking(true);
47 m_parent = parent;
48}
49
50void Viewport::setCanvas(QWidget *canvas)
51{
52 if (m_canvas) {
53 m_canvas->hide();
54 delete m_canvas;
55 }
57 if (!canvas) return;
58 m_canvas->setParent(this);
60 m_canvas->show();
61}
62
63void Viewport::handleDragEnterEvent(QDragEnterEvent *event)
64{
65 // if not a canvas set then ignore this, makes it possible to assume
66 // we have a canvas in all the support methods.
67 if (!(m_parent->canvas() && m_parent->canvas()->canvasWidget())) {
68 event->ignore();
69 return;
70 }
71
72 delete m_draggedShape;
74
75 // only allow dropping when active layer is editable
76 KoSelection *selection = m_parent->canvas()->shapeManager()->selection();
77 KoShapeLayer *activeLayer = selection->activeLayer();
78 if (activeLayer && (!activeLayer->isShapeEditable() || activeLayer->isGeometryProtected())) {
79 event->ignore();
80 return;
81 }
82
83 const QMimeData *data = event->mimeData();
84
85 if (data->hasFormat(SHAPETEMPLATE_MIMETYPE) ||
86 data->hasFormat(SHAPEID_MIMETYPE) ||
87 data->hasFormat("image/svg+xml"))
88 {
89 if (data->hasFormat("image/svg+xml")) {
91 QSizeF fragmentSize;
92
93 QList<KoShape*> shapes = KoSvgPaste::fetchShapesFromData(data->data("image/svg+xml"),
94 canvas->shapeController()->documentRectInPixels(),
95 canvas->shapeController()->pixelsPerInch(),
96 &fragmentSize);
97
98 if (!shapes.isEmpty()) {
99 m_draggedShape = shapes[0];
100 }
101 }
102 else {
103 QByteArray itemData;
104 bool isTemplate = true;
105
106 if (data->hasFormat(SHAPETEMPLATE_MIMETYPE)) {
107 itemData = data->data(SHAPETEMPLATE_MIMETYPE);
108 }
109 else if (data->hasFormat(SHAPEID_MIMETYPE)) {
110 isTemplate = false;
111 itemData = data->data(SHAPEID_MIMETYPE);
112 }
113
114
115 QDataStream dataStream(&itemData, QIODevice::ReadOnly);
116 QString id;
117 dataStream >> id;
118 QString properties;
119 if (isTemplate)
120 dataStream >> properties;
121
122 // and finally, there is a point.
123 QPointF offset;
124 dataStream >> offset;
125
126 // The rest of this method is mostly a copy paste from the KoCreateShapeStrategy
127 // So, lets remove this again when Zagge adds his new class that does this kind of thing. (KoLoadSave)
129 if (! factory) {
130 warnFlake << "Application requested a shape that is not registered '" <<
131 id << "', Ignoring";
132 event->ignore();
133 return;
134 }
135 if (isTemplate) {
136 KoProperties props;
137 props.load(properties);
138 m_draggedShape = factory->createShape(&props, m_parent->canvas()->shapeController()->resourceManager());
139 }
140 else {
141 m_draggedShape = factory->createDefaultShape(m_parent->canvas()->shapeController()->resourceManager());
142 }
143
144 if (m_draggedShape->shapeId().isEmpty()) {
145 m_draggedShape->setShapeId(factory->id());
146 }
147 }
148
149 event->setDropAction(Qt::CopyAction);
150 event->accept();
151
152 Q_ASSERT(m_draggedShape);
153 if (!m_draggedShape) return;
154
155 // calculate maximum existing shape zIndex
156
157 int pasteZIndex = 0;
158
159 {
160 QList<KoShape*> allShapes = m_parent->canvas()->shapeManager()->topLevelShapes();
161
162 if (!allShapes.isEmpty()) {
163 std::sort(allShapes.begin(), allShapes.end(), KoShape::compareShapeZIndex);
164 pasteZIndex = qMin(int(KoShape::maxZIndex), allShapes.last()->zIndex() + 1);
165 }
166 }
167
168 m_draggedShape->setZIndex(pasteZIndex);
170
171 m_parent->canvas()->shapeManager()->addShape(m_draggedShape);
172 } else {
173 event->ignore();
174 }
175}
176
177void Viewport::handleDropEvent(QDropEvent *event)
178{
179 if (!m_draggedShape) {
180 m_parent->canvas()->toolProxy()->dropEvent(event, correctPosition(event->pos()));
181 return;
182 }
183
185 m_parent->canvas()->shapeManager()->remove(m_draggedShape); // remove it to not interfere with z-index calc.
186
187 m_draggedShape->setPosition(QPointF(0, 0)); // always save position.
188 QPointF newPos = correctPosition(event->pos());
189 m_parent->canvas()->clipToDocument(m_draggedShape, newPos); // ensure the shape is dropped inside the document.
191
192
193 KUndo2Command * cmd = m_parent->canvas()->shapeController()->addShape(m_draggedShape, 0);
194
195 if (cmd) {
196 m_parent->canvas()->addCommand(cmd);
197 KoSelection *selection = m_parent->canvas()->shapeManager()->selection();
198
199 // repaint selection before selecting newly create shape
200 Q_FOREACH (KoShape * shape, selection->selectedShapes()) {
201 shape->update();
202 }
203
204 selection->deselectAll();
205 selection->select(m_draggedShape);
206 } else {
207
208 delete m_draggedShape;
209 }
210
211 m_draggedShape = 0;
212}
213
214QPointF Viewport::correctPosition(const QPoint &point) const
215{
216 KisCanvas2 *kisCanvas = dynamic_cast<KisCanvas2*>(m_parent->canvas());
217 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(kisCanvas, QPointF());
218 return kisCanvas->coordinatesConverter()->widgetToDocument(point);
219}
220
221void Viewport::handleDragMoveEvent(QDragMoveEvent *event)
222{
223 if (!m_draggedShape) {
224 m_parent->canvas()->toolProxy()->dragMoveEvent(event, correctPosition(event->pos()));
225 return;
226 }
227
233}
234
236{
237 KisCanvas2 *kisCanvas = dynamic_cast<KisCanvas2*>(m_parent->canvas());
239
240 QRect updateRect = kisCanvas->coordinatesConverter()->documentToWidget(shape->boundingRect()).toAlignedRect();
241 updateRect.adjust(-2, -2, 2, 2); // adjust for antialias
242 update(updateRect);
243}
244
245void Viewport::handleDragLeaveEvent(QDragLeaveEvent *event)
246{
247 if (m_draggedShape) {
249 m_parent->canvas()->shapeManager()->remove(m_draggedShape);
250 delete m_draggedShape;
251 m_draggedShape = 0;
252 } else {
253 m_parent->canvas()->toolProxy()->dragLeaveEvent(event);
254 }
255}
256
257void Viewport::handlePaintEvent(QPainter &painter, QPaintEvent *event)
258{
259 Q_UNUSED(event);
260 if (m_draggedShape) {
261 const KoViewConverter *vc = m_parent->canvas()->viewConverter();
262
263 painter.save();
264 painter.setOpacity(0.6);
265 painter.setRenderHint(QPainter::Antialiasing);
266 painter.setTransform(vc->documentToView());
267 m_draggedShape->paint(painter);
268 painter.restore();
269 }
270}
271
273{
274 const int viewH = size().height();
275 const int viewW = size().width();
276
277 if (m_canvas) {
278 QRect geom = QRect(0, 0, viewW, viewH);
279 if (m_canvas->geometry() != geom) {
280 m_canvas->setGeometry(geom);
281 m_canvas->update();
282 }
283 }
284}
#define warnFlake
Definition FlakeDebug.h:16
#define SHAPETEMPLATE_MIMETYPE
#define SHAPEID_MIMETYPE
KisCoordinatesConverter * coordinatesConverter
_Private::Traits< T >::Result widgetToDocument(const T &obj) const
_Private::Traits< T >::Result documentToWidget(const T &obj) const
QPointer< KoCanvasBase > canvas
const T value(const QString &id) const
void load(const QDomElement &root)
void deselectAll()
clear the selections list
void select(KoShape *shape)
const QList< KoShape * > selectedShapes() const
KoShapeLayer * activeLayer() const
virtual KoShape * createDefaultShape(KoDocumentResourceManager *documentResources=0) const
virtual KoShape * createShape(const KoProperties *params, KoDocumentResourceManager *documentResources=0) const
static KoShapeRegistry * instance()
void setZIndex(qint16 zIndex)
Definition KoShape.cpp:954
QString shapeId() const
Definition KoShape.cpp:1057
virtual bool isShapeEditable(bool recursive=true) const
checks recursively if the shape or one of its parents is not visible or locked
Definition KoShape.cpp:1165
static bool compareShapeZIndex(KoShape *s1, KoShape *s2)
Definition KoShape.cpp:434
bool isGeometryProtected() const
Definition KoShape.cpp:1024
virtual QRectF boundingRect() const
Get the bounding box of the shape.
Definition KoShape.cpp:335
virtual void update() const
Definition KoShape.cpp:605
virtual void paint(QPainter &painter) const =0
Paint the shape fill The class extending this one is responsible for painting itself....
virtual void setPosition(const QPointF &position)
Set the position of the shape in pt.
Definition KoShape.cpp:295
void setShapeId(const QString &id)
Definition KoShape.cpp:1062
void setAbsolutePosition(const QPointF &newPosition, KoFlake::AnchorPosition anchor=KoFlake::Center)
Definition KoShape.cpp:668
static const qint16 maxZIndex
Definition KoShape.h:502
static QList< KoShape * > fetchShapesFromData(const QByteArray &data, QRectF viewportInPx, qreal resolutionPPI, QSizeF *fragmentSize=nullptr)
virtual QPointF documentToView(const QPointF &documentPoint) const
void handleDragEnterEvent(QDragEnterEvent *event)
void handleDragLeaveEvent(QDragLeaveEvent *event)
void handleDropEvent(QDropEvent *event)
KoCanvasControllerWidget * m_parent
Viewport(KoCanvasControllerWidget *parent)
void handleDragMoveEvent(QDragMoveEvent *event)
void setCanvas(QWidget *canvas)
QPointF correctPosition(const QPoint &point) const
void handlePaintEvent(QPainter &gc, QPaintEvent *event)
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128