Krita Source Code Documentation
Loading...
Searching...
No Matches
KisToolKnife.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2025 Agata Cacko
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include "KisToolKnife.h"
8
9#include "QApplication"
10#include "QPainterPath"
11
12#include <klocalizedstring.h>
13#include <KoColor.h>
14#include <KisViewManager.h>
15#include "kis_canvas2.h"
16#include "kis_cursor.h"
17#include "kis_painter.h"
18#include "kis_paintop_preset.h"
19#include "kis_shape_layer.h"
20
21#include "kundo2magicstring.h"
22#include "kundo2stack.h"
24#include "kis_transaction.h"
25#include "KoPathShape.h"
26
28#include "kis_datamanager.h"
30
33
36
38
41
42#include "kis_paint_layer.h"
43#include "kis_algebra_2d.h"
45#include <KoSelection.h>
46#include <KoShapeManager.h>
47
48
51 QPointF startPoint = QPointF(0, 0);
52 QPointF endPoint = QPointF(0, 0);
53 QRectF previousLineDirtyRect = QRectF();
54};
55
56
58 : KoInteractionTool(canvas),
59 m_d(new Private)
60{
61 setObjectName("tool_knife");
62 useCursor(Qt::ArrowCursor);
64}
65
67{
68 m_d->optionsWidget = nullptr;
69}
70
71void paintSelectedEdge(QPainter &painter, const KoViewConverter &converter, const QLineF &lineSegment)
72{
73 QLineF lineInView = converter.documentToView().map(lineSegment);
74 QList<QLineF> parallels = KisAlgebra2D::getParallelLines(lineInView, 5);
75
76 painter.save();
77 qreal width = 2;
78 QColor color = Qt::blue;
79 color.setAlphaF(0.8);
80 QColor white = Qt::white;
81 white.setAlphaF(0.75);
82
83 QPen pen = QPen(color, width);
84 QPen alternative = QPen(white, width);
85
86 alternative.setStyle(Qt::CustomDashLine);
87 qreal dashLength = 6;
88 alternative.setDashPattern({dashLength - 1, dashLength + 1});
89 alternative.setCapStyle(Qt::RoundCap);
90
91 pen.setCosmetic(true);
92 painter.setPen(pen);
93
94 //painter.drawLines(parallels.toVector());
95 painter.drawLine(lineInView);
96
97 alternative.setCosmetic(true);
98 painter.setPen(alternative);
99 //painter.drawLines(parallels.toVector());
100 painter.drawLine(lineInView);
101
102
103 painter.restore();
104
105}
106
107QPolygonF createDiamond(int size, QPointF location = QPointF())
108{
109 QPolygonF polygon;
110 polygon << QPointF(-size, 0);
111 polygon << QPointF(0, size);
112 polygon << QPointF(size, 0);
113 polygon << QPointF(0, -size);
114 polygon.translate(location);
115 return polygon;
116}
117
118void paintSelectedPoint(QPainter &painter, const KoViewConverter &converter, const QPointF &point)
119{
120 QPointF p = point;
121 p = converter.documentToView().map(p);
122 QPolygonF diamond = createDiamond(6, p);
123 painter.save();
124 QColor color = Qt::blue;
125 color.setAlphaF(0.9);
126 QColor white = Qt::white;
127 white.setAlphaF(0.75);
128
129 QPen pen = QPen(color, 2);
130 pen.setCosmetic(true);
131 QBrush brush = QBrush(white);
132 painter.setPen(pen);
133 painter.setBrush(brush);
134
135 painter.drawPolygon(diamond);
136 painter.restore();
137}
138
139void KisToolKnife::paint(QPainter &painter, const KoViewConverter &converter)
140{
141 Q_UNUSED(converter);
142
143 painter.save();
144 painter.restore();
145
146 painter.save();
147 painter.setBrush(Qt::darkGray);
148 //painter.drawEllipse(converter.documentToView(m_d->mousePoint), 4, 4);
149
150 painter.restore();
151
152 KoInteractionTool::paint(painter, converter);
153
154
155#ifdef KNIFE_DEBUG
156 bool paintSelection = true;
157 if (paintSelection) {
158
160 KIS_SAFE_ASSERT_RECOVER_RETURN(canvas()->selectedShapesProxy());
161
162 KIS_SAFE_ASSERT_RECOVER_RETURN(canvas()->selectedShapesProxy()->selection());
163
165
166 QList<KoShape*> shapes = selection->selectedEditableShapes();
167
168 Q_FOREACH(KoShape* shape, shapes) {
170 painter.save();
171 painter.setTransform(painter.transform());
172 for (int i = 0; i < vector.segmentsCount(); i++) {
173 paintSelectedEdge(painter, converter, shape->absoluteTransformation().map(vector.segmentAtAsLine(i)));
174 }
175 for (int i = 0; i < vector.pointsCount(); i++) {
176 paintSelectedPoint(painter, converter, shape->absoluteTransformation().map(vector.pointAt(i).endPoint));
177 }
178 painter.restore();
179
180 }
181 }
182#endif
183
184
185}
186
187void KisToolKnife::activate(const QSet<KoShape *> &shapes)
188{
191
192}
193
198
200{
201 // this tool only works on a vector layer right now, so give a warning if another layer type is trying to use it
202 if (!isValidForCurrentLayer()) {
203 KisCanvas2 *kiscanvas = static_cast<KisCanvas2 *>(canvas());
204 kiscanvas->viewManager()->showFloatingMessage(
205 i18n("This tool only works on vector layers. You probably want to create a vector layer and a starting shape first."),
206 QIcon(), 2000, KisFloatingMessage::Medium, Qt::AlignCenter);
207 return;
208 }
209
211}
212
214{
216
217 if (event->buttons().testFlag(Qt::MouseButton::LeftButton)) {
218
219 m_d->endPoint = event->point;
220 QRectF dirtyRect;
221 KisAlgebra2D::accumulateBounds(m_d->startPoint, &dirtyRect);
222 KisAlgebra2D::accumulateBounds(m_d->endPoint, &dirtyRect);
223
224 QRectF accumulatedWithPrevious = m_d->previousLineDirtyRect;
225 accumulatedWithPrevious |= dirtyRect;
226
227 canvas()->updateCanvas(accumulatedWithPrevious);
228 m_d->previousLineDirtyRect = dirtyRect;
229
230 }
231
233}
234
236{
238
239 m_d->endPoint = event->point;
240
241 QRectF dirtyRect;
242 KisAlgebra2D::accumulateBounds(m_d->startPoint, &dirtyRect);
243 KisAlgebra2D::accumulateBounds(m_d->endPoint, &dirtyRect);
244
245 QRectF accumulatedWithPrevious = m_d->previousLineDirtyRect | dirtyRect;
246
247 canvas()->updateCanvas(accumulatedWithPrevious);
248 m_d->previousLineDirtyRect = dirtyRect;
249}
250
252{
253 QList<KoShape*> shapes = canvas()->shapeManager()->shapes();
254
255 if (m_d->optionsWidget->getToolMode() == KisToolKnifeOptionsWidget::ToolMode::AddGutter) {
256 return new CutThroughShapeStrategy(this, canvas()->selectedShapesProxy()->selection(), shapes, event->point, m_d->optionsWidget->getCurrentWidthsConfig());
257 } else {
258 return new RemoveGutterStrategy(this, canvas()->selectedShapesProxy()->selection(), shapes, event->point);
259 }
260
261 //return NULL;
262}
263
265{
266 KisCanvas2 *kisCanvas = static_cast<KisCanvas2 *>(canvas());
268 const KisShapeLayer *shapeLayer = qobject_cast<const KisShapeLayer*>(node.data());
269 return (shapeLayer != nullptr);
270}
271
273{
274 KisCanvas2 * kiscanvas = dynamic_cast<KisCanvas2*>(canvas());
275 KIS_ASSERT(kiscanvas);
276 qreal resolution = 1.0;
277 if (kiscanvas->image()) {
278 // we're going to assume isotropic image
279 resolution = kiscanvas->image()->xRes();
280 }
281
282 m_d->optionsWidget = new KisToolKnifeOptionsWidget(kiscanvas->viewManager()->canvasResourceProvider(), 0, toolId(), resolution);
283 m_d->optionsWidget->setObjectName(toolId() + "option widget");
284
285
286 return m_d->optionsWidget;
287}
288
const Params2D p
void paintSelectedEdge(QPainter &painter, const KoViewConverter &converter, const QLineF &lineSegment)
QPolygonF createDiamond(int size, QPointF location=QPointF())
void paintSelectedPoint(QPainter &painter, const KoViewConverter &converter, const QPointF &point)
VectorPathPoint pointAt(int i) const
QLineF segmentAtAsLine(int i) const
KisImageWSP image() const
KisViewManager * viewManager() const
static QCursor arrowCursor()
Definition kis_cursor.cc:24
double xRes() const
void mouseMoveEvent(KoPointerEvent *event) override
KisToolKnife(KoCanvasBase *canvas)
~KisToolKnife() override
void mousePressEvent(KoPointerEvent *event)
void mouseReleaseEvent(KoPointerEvent *event) override
void deactivate() override
void paint(QPainter &painter, const KoViewConverter &converter) override
const QScopedPointer< Private > m_d
KoInteractionStrategy * createStrategy(KoPointerEvent *event) override
QWidget * createOptionWidget() override
void activate(const QSet< KoShape * > &shapes) override
bool isValidForCurrentLayer() const
KisCanvasResourceProvider * canvasResourceProvider()
void showFloatingMessage(const QString &message, const QIcon &icon, int timeout=4500, KisFloatingMessage::Priority priority=KisFloatingMessage::Medium, int alignment=Qt::AlignCenter|Qt::TextWordWrap)
shows a floating message in the top right corner of the canvas
virtual KoShapeManager * shapeManager() const =0
virtual void updateCanvas(const QRectF &rc)=0
virtual KoSelectedShapesProxy * selectedShapesProxy() const =0
selectedShapesProxy() is a special interface for keeping a persistent connections to selectionChanged...
void mouseReleaseEvent(KoPointerEvent *event) override
void mouseMoveEvent(KoPointerEvent *event) override
void paint(QPainter &painter, const KoViewConverter &converter) override
void mousePressEvent(KoPointerEvent *event) override
Qt::MouseButtons buttons() const
return buttons pressed (see QMouseEvent::buttons());
QPointF point
The point in document coordinates.
virtual KoSelection * selection()=0
QList< KoShape * > shapes
virtual QPainterPath outline() const
Definition KoShape.cpp:559
QTransform absoluteTransformation() const
Definition KoShape.cpp:335
KoCanvasBase * canvas() const
Returns the canvas the tool is working on.
Q_INVOKABLE QString toolId() const
virtual KoToolSelection * selection()
virtual void repaintDecorations()
void useCursor(const QCursor &cursor)
virtual void activate(const QSet< KoShape * > &shapes)
virtual void deactivate()
virtual QPointF documentToView(const QPointF &documentPoint) const
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
void accumulateBounds(const Point &pt, Rect *bounds)
QList< QLineF > getParallelLines(const QLineF &line, const qreal distance)
KisToolKnifeOptionsWidget * optionsWidget