Krita Source Code Documentation
Loading...
Searching...
No Matches
RemoveGutterStrategy Class Reference

#include <RemoveGutterStrategy.h>

+ Inheritance diagram for RemoveGutterStrategy:

Public Member Functions

KUndo2CommandcreateCommand () override
 
void finishInteraction (Qt::KeyboardModifiers modifiers) override
 
void handleMouseMove (const QPointF &mouseLocation, Qt::KeyboardModifiers modifiers) override
 
void paint (QPainter &painter, const KoViewConverter &converter, const KoColorDisplayRendererInterface *displayRendererInterface) override
 
 RemoveGutterStrategy (KoToolBase *tool, KoSelection *selection, const QList< KoShape * > &shapes, QPointF startPoint)
 
 ~RemoveGutterStrategy () override
 
- Public Member Functions inherited from KoInteractionStrategy
virtual void cancelInteraction ()
 
 KoInteractionStrategy (KoToolBase *parent)
 constructor
 
KoToolBasetool () const
 
virtual ~KoInteractionStrategy ()
 Destructor.
 

Private Attributes

QList< KoShape * > m_allShapes
 
QPointF m_endPoint = QPointF()
 
QRectF m_previousLineDirtyRect = QRectF()
 
QList< KoShape * > m_selectedShapes
 
QPointF m_startPoint = QPointF()
 

Additional Inherited Members

- Protected Member Functions inherited from KoInteractionStrategy
uint decorationThickness () const
 
uint grabSensitivity () const
 Convenience function to get the global grab sensitivity.
 
uint handleRadius () const
 Convenience function to get the global handle radius.
 
 KoInteractionStrategy (KoInteractionStrategyPrivate &)
 constructor
 
- Protected Attributes inherited from KoInteractionStrategy
KoInteractionStrategyPrivated_ptr
 

Detailed Description

Definition at line 18 of file RemoveGutterStrategy.h.

Constructor & Destructor Documentation

◆ RemoveGutterStrategy()

RemoveGutterStrategy::RemoveGutterStrategy ( KoToolBase * tool,
KoSelection * selection,
const QList< KoShape * > & shapes,
QPointF startPoint )

Definition at line 31 of file RemoveGutterStrategy.cpp.

33 , m_startPoint(startPoint)
34 , m_endPoint(startPoint)
35{
37 m_allShapes = shapes;
38}
KoInteractionStrategy(KoToolBase *parent)
constructor
const QList< KoShape * > selectedEditableShapes() const
QList< KoShape * > m_allShapes
QList< KoShape * > m_selectedShapes

References m_allShapes, m_selectedShapes, and KoSelection::selectedEditableShapes().

◆ ~RemoveGutterStrategy()

RemoveGutterStrategy::~RemoveGutterStrategy ( )
override

Definition at line 40 of file RemoveGutterStrategy.cpp.

41{
42
43}

Member Function Documentation

◆ createCommand()

KUndo2Command * RemoveGutterStrategy::createCommand ( )
overridevirtual

For interactions that are undo-able this method should be implemented to return such a command. Implementations should return 0 otherwise.

Returns
a command, or 0.

Implements KoInteractionStrategy.

Definition at line 45 of file RemoveGutterStrategy.cpp.

46{
47 return 0;
48}

◆ finishInteraction()

void RemoveGutterStrategy::finishInteraction ( Qt::KeyboardModifiers modifiers)
overridevirtual

Override to make final changes to the data on the end of an interaction.

Implements KoInteractionStrategy.

Definition at line 98 of file RemoveGutterStrategy.cpp.

99{
101
102
103 KisCanvas2 *kisCanvas = static_cast<KisCanvas2 *>(tool()->canvas());
105 const QTransform booleanWorkaroundTransform = KritaUtils::pathShapeBooleanSpaceWorkaround(kisCanvas->image());
106
107 QList<QPainterPath> srcOutlines;
108 QList<QPainterPath> srcOutlinesOutside;
109
110 if (m_allShapes.length() == 0) {
111 qCritical() << "No shapes on the layer";
112 return;
113 }
114
115 QList<bool> isSelected = QList<bool>();
116 isSelected.reserve(m_allShapes.length());
117 for (int i = 0; i < m_allShapes.length(); i++) {
118 isSelected.append(m_selectedShapes.contains(m_allShapes[i]));
119 }
120
121 QLineF mouseLine = QLineF(m_startPoint, m_endPoint);
123
124 mouseLine = booleanWorkaroundTransform.map(mouseLine);
125 lineRect = KisAlgebra2D::createRectFromCorners(mouseLine);
126
127#ifdef KNIFE_DEBUG
128 convertShapeToDebugArray(mouseLine);
129 convertShapeToDebugArray(lineRect);
130#endif
131
132
133 QList<int> indexes;
134 QList<int> indexesOutside;
135
136 for (int i = 0; i < m_allShapes.length(); i++) {
137 KoShape* shape = m_allShapes[i];
138 QPainterPath outlineHere =
139 booleanWorkaroundTransform.map(
140 shape->absoluteTransformation().map(
141 shape->outline()));
142#ifdef KNIFE_DEBUG
143 convertShapeToDebugArray(outlineHere);
144#endif
145 if (outlineHere.boundingRect().intersects(lineRect)) {
146 srcOutlines << outlineHere;
147 indexes << i;
148 //outlineRect |= outlineHere.boundingRect();
149 } else {
150 srcOutlinesOutside << outlineHere;
151 indexesOutside << i;
152 }
153 }
154
155 if (srcOutlines.isEmpty()) {
156 return;
157 }
158
159
160 QList<int> shapeNewIndexes;
161 QList<int> shapeOrigIndexes;
162 QList<int> lineSegmentIndexes;
163
164
165 for (int i = 0; i < srcOutlines.length(); i++) {
166 QList<int> lineIndexes = KisAlgebra2D::getLineSegmentCrossingLineIndexes(mouseLine, srcOutlines[i]);
167 int shapeOrigIndex = indexes[i];
168
169 if (lineIndexes.length() > 0) {
170 Q_FOREACH(int lineIndex, lineIndexes) {
171 shapeNewIndexes << i;
172 lineSegmentIndexes << lineIndex;
173 shapeOrigIndexes << shapeOrigIndex;
174 }
175 } else {
176 srcOutlinesOutside << srcOutlines[i];
177 indexesOutside << shapeOrigIndex;
178 }
179 }
180
181 if (shapeNewIndexes.length() != 2) {
182#ifdef KNIFE_DEBUG
183 qCritical() << "Shape indexes count isn't correct: " << ppVar(shapeNewIndexes.length()) << ppVar(lineSegmentIndexes.length());
184 qCritical() << "Mouse line in used coordinates: " << mouseLine;
185 qCritical() << "Number of shapes even considered: " << srcOutlines.length();
186 Q_FOREACH(QPainterPath path, srcOutlines) {
187 qCritical() << "> A path: ";
188 convertShapeToDebugArray(path);
189 }
190 qCritical() << "That's the end of shapes considered.";
191 qCritical() << "Shapes not considered: " << srcOutlinesOutside.length();
192 Q_FOREACH(QPainterPath path, srcOutlinesOutside) {
193 qCritical() << "> A path: ";
194 convertShapeToDebugArray(path);
195 }
196 qCritical() << "That's the end of shapes not considered.";
197 for(int i = 0; i < shapeNewIndexes.length(); i++) {
198 int index = shapeNewIndexes[i];
199 qCritical() << "Shape: ";
200 convertShapeToDebugArray(srcOutlines[index]);
201 qCritical() << "Line index: " << lineSegmentIndexes[i] << " meaning it's: " << srcOutlines[index].elementAt(KisAlgebra2D::wrapValue(lineSegmentIndexes[i], 0, srcOutlines[index].elementCount()))
202 << srcOutlines[index].elementAt(KisAlgebra2D::wrapValue(lineSegmentIndexes[i] + 1, 0, srcOutlines[index].elementCount()));
203 }
204 // TODO: this if should end here; code below adds a debug line showing the mouse line
205
206 QPainterPath newLineShape = QPainterPath();
207 newLineShape.moveTo(mouseLine.p1());
208 newLineShape.lineTo(mouseLine.p2());
209
210 newLineShape = booleanWorkaroundTransform.inverted().map(newLineShape);
211 KoPathShape* newLineShapeToAdd = KoPathShape::createShapeFromPainterPath(newLineShape);
212
213 newLineShapeToAdd->setBackground(m_allShapes[0]->background());
214 newLineShapeToAdd->setStroke(m_allShapes[0]->stroke());
215 newLineShapeToAdd->setZIndex(m_allShapes[0]->zIndex() + 100);
216
217
218
219 KUndo2Command *cmd = new KUndo2Command(kundo2_i18n("Knife tool: cut through shapes"));
220 tool()->canvas()->shapeController()->addShapeDirect(newLineShapeToAdd, m_allShapes[0]->parent(), cmd);
221 tool()->canvas()->addCommand(cmd);
222
223#endif
224
225 return;
226 }
227
228
229#ifdef KNIFE_DEBUG
230 qCritical() << "Found two shapes.";
231 qCritical() << "Shape 1:";
232 convertShapeToDebugArray(srcOutlines[shapeNewIndexes[0]]);
233 qCritical() << ppVar(srcOutlines[shapeNewIndexes[0]].toFillPolygon());
234
235 qCritical() << "Shape 2:";
236 convertShapeToDebugArray(srcOutlines[shapeNewIndexes[1]]);
237 qCritical() << ppVar(srcOutlines[shapeNewIndexes[1]].toFillPolygon());
238#endif
239
240 if (shapeNewIndexes[0] == shapeNewIndexes[1]) {
241 // the same shape
242 // gotta ensure the mouseline starts and ends inside
243 bool insideP1 = KisAlgebra2D::isInsideShape(srcOutlines[shapeNewIndexes[0]], mouseLine.p1());
244 bool insideP2 = KisAlgebra2D::isInsideShape(srcOutlines[shapeNewIndexes[0]], mouseLine.p2());
245 if (!insideP1 || !insideP2) {
246 // it's from outside, it doesn't go over a gutter, then
247 return;
248 }
249 }
250
251
252
253 QPainterPath result = KisAlgebra2D::removeGutterSmart(srcOutlines[shapeNewIndexes[0]], lineSegmentIndexes[0], srcOutlines[shapeNewIndexes[1]], lineSegmentIndexes[1], shapeNewIndexes[0]==shapeNewIndexes[1]);
254
255#ifdef KNIFE_DEBUG
256 qCritical() << "Finally got a result:";
257 convertShapeToDebugArray(result);
258 qCritical() << ppVar(result.toFillPolygon());
259#endif
260
261 QList<KoShape*> resultSelectedShapes;
262
263 Q_FOREACH(int index, indexesOutside) {
264 if (isSelected[index]) {
265 resultSelectedShapes << m_allShapes[index];
266 }
267 }
268
269 // since we can't really decide which style to use, we're gonna use the style of the first found shape.
270 // if the user doesn't like it, they can change it.
271
272
273 result = booleanWorkaroundTransform.inverted().map(result);
275 resultShape->closeMerge();
276
277 if (resultShape->boundingRect().isEmpty()) {
278 return;
279 }
280
281 KUndo2Command *cmd = new KUndo2Command(kundo2_i18n("Knife tool: remove a gutter"));
282
283
284
286
287
288 KoShape* referenceShape = m_allShapes[shapeOrigIndexes[0]];
289 KoPathShape* koPathReferenceShape = dynamic_cast<KoPathShape*>(referenceShape);
290 resultShape->setBackground(referenceShape->background());
291 resultShape->setStroke(referenceShape->stroke());
292 resultShape->setZIndex(referenceShape->zIndex());
293 if (koPathReferenceShape) {
294 resultShape->setFillRule(koPathReferenceShape->fillRule());
295 }
296
297
298 KoShapeContainer *parent = referenceShape->parent();
299 tool()->canvas()->shapeController()->addShapeDirect(resultShape, parent, cmd);
300
301 if (isSelected[shapeOrigIndexes[0]] || isSelected[shapeOrigIndexes[1]]) { // if either is selected
302 resultSelectedShapes << resultShape;
303 }
304
305 QList<KoShape*> shapesToRemove;
306 shapesToRemove << m_allShapes[shapeOrigIndexes[0]];
307 if (shapeOrigIndexes[0] != shapeOrigIndexes[1]) { // there is a good reason in the workflow to allow doing this operation on the same shape
308 shapesToRemove << m_allShapes[shapeOrigIndexes[1]];
309 }
310
311
312 tool()->canvas()->shapeController()->removeShapes(shapesToRemove, cmd);
313 new KoKeepShapesSelectedCommand({}, resultSelectedShapes, tool()->canvas()->selectedShapesProxy(), true, cmd);
314 tool()->canvas()->addCommand(cmd);
315
316
317}
KisImageWSP image() const
QPointer< KoShapeController > shapeController
virtual void updateCanvas(const QRectF &rc)=0
virtual void addCommand(KUndo2Command *command)=0
virtual KoSelectedShapesProxy * selectedShapesProxy() const =0
selectedShapesProxy() is a special interface for keeping a persistent connections to selectionChanged...
The position of a path point within a path shape.
Definition KoPathShape.h:63
Qt::FillRule fillRule() const
Returns the fill rule for the path object.
void closeMerge()
Closes the current subpath.
void setFillRule(Qt::FillRule fillRule)
Sets the fill rule to be used for painting the background.
QRectF boundingRect() const override
reimplemented
static KoPathShape * createShapeFromPainterPath(const QPainterPath &path)
Creates path shape from given QPainterPath.
void setZIndex(qint16 zIndex)
Definition KoShape.cpp:782
virtual QPainterPath outline() const
Definition KoShape.cpp:554
virtual void setStroke(KoShapeStrokeModelSP stroke)
Definition KoShape.cpp:899
QTransform absoluteTransformation() const
Definition KoShape.cpp:330
virtual void setBackground(QSharedPointer< KoShapeBackground > background)
Definition KoShape.cpp:746
KoCanvasBase * canvas() const
Returns the canvas the tool is working on.
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define ppVar(var)
Definition kis_debug.h:155
KUndo2MagicString kundo2_i18n(const char *text)
T wrapValue(T value, T wrapBounds)
QPainterPath removeGutterSmart(const QPainterPath &shape1, int index1, const QPainterPath &shape2, int index2, bool isSameShape)
removeGutterSmart
bool isInsideShape(const VectorPath &path, const QPointF &point)
QList< int > getLineSegmentCrossingLineIndexes(const QLineF &line, const QPainterPath &shape)
PointTypeTraits< Point >::rect_type createRectFromCorners(Point corner1, Point corner2)
ChildIterator< value_type, is_const > parent(const ChildIterator< value_type, is_const > &it)
Definition KisForest.h:327
QTransform pathShapeBooleanSpaceWorkaround(KisImageSP image)

References KoShape::absoluteTransformation(), KoCanvasBase::addCommand(), KoPathShape::boundingRect(), KoToolBase::canvas(), KoPathShape::closeMerge(), KisAlgebra2D::createRectFromCorners(), KoPathShape::createShapeFromPainterPath(), KoPathShape::fillRule(), KisAlgebra2D::getLineSegmentCrossingLineIndexes(), KisCanvas2::image(), KisAlgebra2D::isInsideShape(), KIS_SAFE_ASSERT_RECOVER_RETURN, kundo2_i18n(), m_allShapes, m_endPoint, m_previousLineDirtyRect, m_selectedShapes, m_startPoint, KoShape::outline(), KritaUtils::pathShapeBooleanSpaceWorkaround(), ppVar, KisAlgebra2D::removeGutterSmart(), KoCanvasBase::selectedShapesProxy(), KoShape::setBackground(), KoPathShape::setFillRule(), KoShape::setStroke(), KoShape::setZIndex(), KoCanvasBase::shapeController, KoInteractionStrategy::tool(), KoCanvasBase::updateCanvas(), and KisAlgebra2D::wrapValue().

◆ handleMouseMove()

void RemoveGutterStrategy::handleMouseMove ( const QPointF & mouseLocation,
Qt::KeyboardModifiers modifiers )
overridevirtual

Extending classes should implement this method to update the selectedShapes based on the new mouse position.

Parameters
mouseLocationthe new location in pt
modifiersOR-ed set of keys pressed.

Implements KoInteractionStrategy.

Definition at line 50 of file RemoveGutterStrategy.cpp.

51{
52 m_endPoint = mouseLocation;
53 QRectF dirtyRect;
56 QLineF l = QLine(QPoint(), QPoint(50, 50));
57
58 l = tool()->canvas()->viewConverter()->viewToDocument().map(l);
59 dirtyRect = kisGrowRect(dirtyRect, l.length()); // twice as much as it should need to account for lines showing the effect
60
61 QRectF accumulatedWithPrevious = m_previousLineDirtyRect | dirtyRect;
62
63 tool()->canvas()->updateCanvas(accumulatedWithPrevious);
64 m_previousLineDirtyRect = dirtyRect;
65}
virtual const KoViewConverter * viewConverter() const =0
virtual QPointF viewToDocument(const QPointF &viewPoint) const
T kisGrowRect(const T &rect, U offset)
Definition kis_global.h:186
void accumulateBounds(const Point &pt, Rect *bounds)

References KisAlgebra2D::accumulateBounds(), KoToolBase::canvas(), kisGrowRect(), m_endPoint, m_previousLineDirtyRect, m_startPoint, KoInteractionStrategy::tool(), KoCanvasBase::updateCanvas(), KoCanvasBase::viewConverter(), and KoViewConverter::viewToDocument().

◆ paint()

void RemoveGutterStrategy::paint ( QPainter & painter,
const KoViewConverter & converter,
const KoColorDisplayRendererInterface * displayRendererInterface )
overridevirtual

Reimplement this if the action needs to draw a "blob" on the canvas; that is, a transient decoration like a rubber band.

Reimplemented from KoInteractionStrategy.

Definition at line 319 of file RemoveGutterStrategy.cpp.

320{
321 painter.save();
322 KoColor c;
323 c.fromQColor(Qt::darkGray);
324 painter.setPen(QPen(QBrush(displayRendererInterface->convertColorToDisplayColorSpace(c)), 2));
325
326 QLineF line = converter.documentToView().map(QLineF(m_startPoint, m_endPoint));
327 if (line.length() > 0) {
328 QPointF vector = line.p2() - line.p1();
329 vector = vector/line.length();
330 int arrowLength = 15;
331 int arrowThickness = 5;
332
333 QPointF before = line.p1() - vector*arrowLength;
334 QPointF after = line.p2() + vector*arrowLength;
335
336 QPointF perpendicular = QPointF(vector.y(), -vector.x());
337
338 painter.drawLine(QPointF(before + arrowThickness*perpendicular), line.p1());
339 painter.drawLine(QPointF(before - arrowThickness*perpendicular), line.p1());
340
341 painter.drawLine(QPointF(after + arrowThickness*perpendicular), line.p2());
342 painter.drawLine(QPointF(after - arrowThickness*perpendicular), line.p2());
343
344
345 }
346 painter.drawLine(line);
347
348 painter.restore();
349
350}
virtual QColor convertColorToDisplayColorSpace(const KoColor color) const =0
convertColorToDisplayColorSpace
void fromQColor(const QColor &c)
Convenient function for converting from a QColor.
Definition KoColor.cpp:213
virtual QPointF documentToView(const QPointF &documentPoint) const

References KoColorDisplayRendererInterface::convertColorToDisplayColorSpace(), KoViewConverter::documentToView(), KoColor::fromQColor(), m_endPoint, and m_startPoint.

Member Data Documentation

◆ m_allShapes

QList<KoShape *> RemoveGutterStrategy::m_allShapes
private

Definition at line 35 of file RemoveGutterStrategy.h.

◆ m_endPoint

QPointF RemoveGutterStrategy::m_endPoint = QPointF()
private

Definition at line 32 of file RemoveGutterStrategy.h.

◆ m_previousLineDirtyRect

QRectF RemoveGutterStrategy::m_previousLineDirtyRect = QRectF()
private

Definition at line 33 of file RemoveGutterStrategy.h.

◆ m_selectedShapes

QList<KoShape *> RemoveGutterStrategy::m_selectedShapes
private

Definition at line 36 of file RemoveGutterStrategy.h.

◆ m_startPoint

QPointF RemoveGutterStrategy::m_startPoint = QPointF()
private

Definition at line 31 of file RemoveGutterStrategy.h.


The documentation for this class was generated from the following files: