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) 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 30 of file RemoveGutterStrategy.cpp.

32 , m_startPoint(startPoint)
33 , m_endPoint(startPoint)
34{
36 m_allShapes = shapes;
37}
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 39 of file RemoveGutterStrategy.cpp.

40{
41
42}

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 44 of file RemoveGutterStrategy.cpp.

45{
46 return 0;
47}

◆ 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 97 of file RemoveGutterStrategy.cpp.

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

50{
51 m_endPoint = mouseLocation;
52 QRectF dirtyRect;
55 QLineF l = QLine(QPoint(), QPoint(50, 50));
56
57 l = tool()->canvas()->viewConverter()->viewToDocument().map(l);
58 dirtyRect = kisGrowRect(dirtyRect, l.length()); // twice as much as it should need to account for lines showing the effect
59
60 QRectF accumulatedWithPrevious = m_previousLineDirtyRect | dirtyRect;
61
62 tool()->canvas()->updateCanvas(accumulatedWithPrevious);
63 m_previousLineDirtyRect = dirtyRect;
64}
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 )
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 318 of file RemoveGutterStrategy.cpp.

319{
320 painter.save();
321 painter.setPen(QPen(QBrush(Qt::darkGray), 2));
322
323 QLineF line = converter.documentToView().map(QLineF(m_startPoint, m_endPoint));
324 if (line.length() > 0) {
325 QPointF vector = line.p2() - line.p1();
326 vector = vector/line.length();
327 int arrowLength = 15;
328 int arrowThickness = 5;
329
330 QPointF before = line.p1() - vector*arrowLength;
331 QPointF after = line.p2() + vector*arrowLength;
332
333 QPointF perpendicular = QPointF(vector.y(), -vector.x());
334
335 painter.drawLine(QPointF(before + arrowThickness*perpendicular), line.p1());
336 painter.drawLine(QPointF(before - arrowThickness*perpendicular), line.p1());
337
338 painter.drawLine(QPointF(after + arrowThickness*perpendicular), line.p2());
339 painter.drawLine(QPointF(after - arrowThickness*perpendicular), line.p2());
340
341
342 }
343 painter.drawLine(line);
344
345 painter.restore();
346
347}
virtual QPointF documentToView(const QPointF &documentPoint) const

References KoViewConverter::documentToView(), 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: