27#include <klocalizedstring.h>
54 if (d->hoveredPoint) {
61 if (d->pointIsDragged) {
65 d->activePoint->parent()->shapeToDocument(
66 d->activePoint->controlPoint2()));
71 if (
canvas()->snapGuide()->isSnapping()) {
87 paintPath(*(d->shape), painter, converter);
93 const bool firstPointActive = d->firstPoint == d->activePoint;
95 if (d->pointIsDragged || firstPointActive) {
96 const bool onlyPaintActivePoints =
false;
99 if (d->activePoint->activeControlPoint1()) {
104 d->activePoint->paint(helper, paintFlags, onlyPaintActivePoints);
107 if (!firstPointActive) {
115 if (
d->hoveredPoint) {
132 painter.transform());
135 pathShape.
paint(painter);
140 pathShape.
stroke()->paint(d->shape, painter);
157 if (event->
button() == Qt::RightButton) {
162 const bool isOverFirstPoint = d->shape &&
165 const bool haveCloseModifier = d->enableClosePathShortcut
167 && d->shape->pointCount() > 2
168 && (
event->modifiers() & Qt::ShiftModifier);
170 if ((event->
button() == Qt::LeftButton) && haveCloseModifier && !isOverFirstPoint) {
175 d->finishAfterThisPoint =
false;
178 if (isOverFirstPoint) {
179 d->activePoint->setPoint(d->firstPoint->point());
183 if (haveCloseModifier) {
184 d->shape->closeMerge();
186 d->existingStartPoint = 0;
192 d->finishAfterThisPoint =
true;
199 d->existingEndPoint = d->endPointAtPosition(point);
200 if (d->existingEndPoint.isValid() && d->existingEndPoint != d->existingStartPoint) {
201 point = d->existingEndPoint.path->shapeToDocument(d->existingEndPoint.point->point());
202 d->activePoint->setPoint(point);
206 d->activePoint->setPoint(point);
214 d->shape = pathShape;
220 stroke->setLineWidth(
canvas()->unit().fromUserValue(size));
221 stroke->setColor(
canvas()->resourceManager()->foregroundColor().toQColor());
227 d->existingStartPoint = d->endPointAtPosition(point);
229 if (d->existingStartPoint.isValid()) {
230 point = d->existingStartPoint.path->shapeToDocument(d->existingStartPoint.point->point());
233 d->activePoint = pathShape->
moveTo(point);
234 d->firstPoint = d->activePoint;
238 d->angleSnapStrategy =
new AngleSnapStrategy(d->angleSnappingDelta, d->angleSnapStatus);
244 d->dragStartPoint =
event->point;
246 if (d->angleSnapStrategy)
247 d->angleSnapStrategy->setStartPoint(d->activePoint->point());
253 return ((
bool) d->shape);
264 d->enableClosePathShortcut =
value;
284 d->hoveredPoint = d->endPointAtPosition(event->
point);
290 d->mouseOverFirstPoint =
false;
298 if (considerDrag && (event->
buttons() & Qt::LeftButton)) {
299 if (d->pointIsDragged ||
302 d->pointIsDragged =
true;
303 QPointF offset = snappedPosition - d->activePoint->point();
304 d->activePoint->setControlPoint2(d->activePoint->point() + offset);
306 if ((event->
modifiers() & Qt::AltModifier) == 0) {
307 d->activePoint->setControlPoint1(d->activePoint->point() - offset);
311 d->activePoint->setPoint(snappedPosition);
313 if (!d->prevPointWasDragged && d->autoSmoothCurves) {
315 if (index.second > 0) {
318 KoPathPoint *prevPoint = d->shape->pointByIndex(prevIndex);
323 if (index.second > 1) {
325 prevPrevPoint = d->shape->pointByIndex(prevPrevIndex);
329 const QPointF control1 = prevPoint->
point() + 0.3 * (prevPrevPoint->
point() - prevPoint->
point());
333 const QPointF control2 = prevPoint->
point() + 0.3 * (d->activePoint->point() - prevPoint->
point());
336 const QPointF activeControl = d->activePoint->point() + 0.3 * (prevPoint->
point() - d->activePoint->point());
337 d->activePoint->setControlPoint1(activeControl);
353 if (! d->shape || (event->
buttons() & Qt::RightButton))
return;
355 d->prevPointWasDragged = d->pointIsDragged;
356 d->pointIsDragged =
false;
359 if (!d->finishAfterThisPoint) {
360 d->activePoint = d->shape->lineTo(event->
point);
368 if (
qFuzzyCompare(diff1.x(), diff2.x()) && qFuzzyCompare(diff1.y(), diff2.y()))
372 if (d->finishAfterThisPoint) {
374 d->firstPoint->setControlPoint1(d->activePoint->controlPoint1());
375 delete d->shape->removePoint(d->shape->pathPointIndex(d->activePoint));
376 d->activePoint = d->firstPoint;
378 if (!d->prevPointWasDragged && d->autoSmoothCurves) {
382 d->shape->closeMerge();
385 d->existingStartPoint = 0;
391 d->angleSnapStrategy->deactivate();
416 delete d->shape->removePoint(d->shape->pathPointIndex(d->activePoint));
444 if (lastPointIndex.second > 1) {
445 lastPointIndex.second--;
446 delete d->shape->removePoint(lastPointIndex);
465 d->loadAutoSmoothValueFromConfig();
484 d->handleRadius = res.toUInt();
488 d->decorationThickness = res.toUInt();
505 d->existingStartPoint.validate(
canvas());
506 d->existingEndPoint.validate(
canvas());
508 if (d->connectPaths(pathShape, d->existingStartPoint, d->existingEndPoint)) {
509 if (d->existingStartPoint.isValid()) {
510 startShape = d->existingStartPoint.path;
512 if (d->existingEndPoint.isValid() && d->existingEndPoint != d->existingStartPoint) {
513 endShape = d->existingEndPoint.path;
517 if (tryMergeOnly && !startShape && !
endShape) {
564 QWidget *widget =
new QWidget();
565 widget->setObjectName(
"bezier-curve-tool-widget");
566 widget->setWindowTitle(i18n(
"Path options"));
568 QCheckBox *smoothCurves =
new QCheckBox(i18n(
"Autosmooth curve"), widget);
569 smoothCurves->setObjectName(
"smooth-curves-widget");
570 smoothCurves->setChecked(d->autoSmoothCurves);
572 QCheckBox *angleSnap =
new QCheckBox(i18n(
"Activate angle snap"), widget);
573 angleSnap->setObjectName(
"angle-snap-widget");
574 angleSnap->setChecked(
false);
575 angleSnap->setCheckable(
true);
578 angleEdit->setObjectName(
"angle-edit-widget");
579 angleEdit->
setAngle(d->angleSnappingDelta);
583 angleEdit->setEnabled(angleSnap->isChecked());
585 QHBoxLayout *angleEditLayout =
new QHBoxLayout;
586 angleEditLayout->setContentsMargins(10, 0, 0, 0);
587 angleEditLayout->setSpacing(0);
588 angleEditLayout->addWidget(angleEdit);
590 QVBoxLayout *mainLayout =
new QVBoxLayout;
591 mainLayout->setContentsMargins(0, 0, 0, 0);
592 mainLayout->setSpacing(5);
594 mainLayout->addWidget(smoothCurves);
595 mainLayout->addWidget(angleSnap);
596 mainLayout->addLayout(angleEditLayout);
598 widget->setLayout(mainLayout);
602 connect(smoothCurves,
603 SIGNAL(toggled(
bool)),
605 SLOT(autoSmoothCurvesChanged(
bool)));
609 SLOT(setChecked(
bool)));
610 connect(angleEdit, SIGNAL(angleChanged(qreal)),
this, SLOT(angleDeltaChanged(qreal)));
611 connect(angleSnap, SIGNAL(stateChanged(
int)),
this, SLOT(
angleSnapChanged(
int)));
613 SIGNAL(toggled(
bool)),
615 SLOT(setEnabled(
bool)));
621#include <moc_KoCreatePathTool.cpp>
float value(const T *src, size_t ch)
QPair< int, int > KoPathPointIndex
A widget with several options to select an angle.
@ FlipOptionsMode_MenuButton
The flip options are shown as a menu accessible via a options button.
void setFlipOptionsMode(FlipOptionsMode newMode)
Sets the mode in which the flip options should be shown.
void setAngle(qreal newAngle)
Sets the current angle.
void setRange(qreal newMinimum, qreal newMaximum)
Sets the minimum and maximum values for the angle.
void setDecimals(int newNumberOfDecimals)
Sets the number of decimals (precision) used by the angle.
The KisHandlePainterHelper class is a special helper for painting handles around objects....
void setHandleStyle(const KisHandleStyle &style)
static KisHandleStyle & primarySelection(KisHandlePalette palette=KisHandlePalette())
static KisHandleStyle & highlightedPrimaryHandles(KisHandlePalette palette=KisHandlePalette())
QPointer< KoShapeController > shapeController
virtual KoShapeManager * shapeManager() const =0
virtual void updateCanvas(const QRectF &rc)=0
virtual KoColorDisplayRendererInterface * displayRendererInterface() const
displayRendererInterface The display renderer interface has a number of color conversion functions wh...
virtual void addCommand(KUndo2Command *command)=0
QPointer< KoCanvasResourceProvider > resourceManager
virtual KisHandlePalette handlePaletteForDisplayColorSpace() const =0
handlePaletteForDisplayColorSpace
static void makeCubicPointSmooth(KoPathPoint *point)
A KoPathPoint represents a point in a path.
void setControlPoint1(const QPointF &point)
Set the control point 1.
void setProperty(PointProperty property)
Sets a single property of a point.
void setControlPoint2(const QPointF &point)
Set the control point 2.
@ IsSymmetric
it is symmetric, like smooth but control points have same distance to point
@ ControlPoint2
the second control point
@ ControlPoint1
the first control point
The position of a path point within a path shape.
virtual QPointF normalize()
Normalizes the path data.
KoPathPoint * moveTo(const QPointF &p)
Starts a new Subpath.
void paint(QPainter &painter) const override
reimplemented
QRectF boundingRect() const override
reimplemented
Qt::MouseButton button() const
return button pressed (see QMouseEvent::button());
Qt::MouseButtons buttons() const
return buttons pressed (see QMouseEvent::buttons());
bool isTouchEvent() const
Qt::KeyboardModifiers modifiers() const
QPointF point
The point in document coordinates.
virtual KoShapeStrokeModelSP stroke() const
virtual void setStroke(KoShapeStrokeModelSP stroke)
QTransform absoluteTransformation() const
virtual void setBackground(QSharedPointer< KoShapeBackground > background)
static KisHandlePainterHelper createHandlePainterHelperView(QPainter *painter, KoShape *shape, const KoViewConverter &converter, qreal handleRadius=0.0, int decorationThickness=1)
virtual QSharedPointer< KoShapeBackground > background() const
void setShapeId(const QString &id)
bool addCustomSnapStrategy(KoSnapStrategy *customStrategy)
void reset()
Resets the snap guide.
void paint(QPainter &painter, const KoViewConverter &converter, const KoColorDisplayRendererInterface *displayRenderer)
paints the guide
void setIgnoredPathPoints(const QList< KoPathPoint * > &ignoredPoints)
Sets a list of path points to ignore.
QPointF snap(const QPointF &mousePosition, Qt::KeyboardModifiers modifiers)
snaps the mouse position, returns if mouse was snapped
void setAdditionalEditedShape(KoShape *shape)
Adds an additional shape to snap to (useful when creating a path)
QRectF boundingRect()
returns the bounding rect of the guide
virtual QPointF documentToView(const QPointF &documentPoint) const
static bool qFuzzyCompare(half p1, half p2)
#define KIS_SAFE_ASSERT_RECOVER(cond)
T kisGrowRect(const T &rect, U offset)
@ DecorationThickness
Integer, the thickness of single px decorations, will be adjusted by HiDPI settings....
@ HandleRadius
The handle radius used for drawing handles of any kind.
rgba palette[MAX_PALETTE]