26#include <klocalizedstring.h>
53 if (d->hoveredPoint) {
60 if (d->pointIsDragged) {
64 d->activePoint->parent()->shapeToDocument(
65 d->activePoint->controlPoint2()));
70 if (
canvas()->snapGuide()->isSnapping()) {
84 paintPath(*(d->shape), painter, converter);
90 const bool firstPointActive = d->firstPoint == d->activePoint;
92 if (d->pointIsDragged || firstPointActive) {
93 const bool onlyPaintActivePoints =
false;
96 if (d->activePoint->activeControlPoint1()) {
101 d->activePoint->paint(helper, paintFlags, onlyPaintActivePoints);
104 if (!firstPointActive) {
112 if (
d->hoveredPoint) {
129 painter.transform());
132 pathShape.
paint(painter);
137 pathShape.
stroke()->paint(d->shape, painter);
154 if (event->
button() == Qt::RightButton) {
159 const bool isOverFirstPoint = d->shape &&
162 const bool haveCloseModifier = d->enableClosePathShortcut
164 && d->shape->pointCount() > 2
165 && (
event->modifiers() & Qt::ShiftModifier);
167 if ((event->
button() == Qt::LeftButton) && haveCloseModifier && !isOverFirstPoint) {
172 d->finishAfterThisPoint =
false;
175 if (isOverFirstPoint) {
176 d->activePoint->setPoint(d->firstPoint->point());
180 if (haveCloseModifier) {
181 d->shape->closeMerge();
183 d->existingStartPoint = 0;
189 d->finishAfterThisPoint =
true;
196 d->existingEndPoint = d->endPointAtPosition(point);
197 if (d->existingEndPoint.isValid() && d->existingEndPoint != d->existingStartPoint) {
198 point = d->existingEndPoint.path->shapeToDocument(d->existingEndPoint.point->point());
199 d->activePoint->setPoint(point);
203 d->activePoint->setPoint(point);
211 d->shape = pathShape;
217 stroke->setLineWidth(
canvas()->unit().fromUserValue(size));
218 stroke->setColor(
canvas()->resourceManager()->foregroundColor().toQColor());
224 d->existingStartPoint = d->endPointAtPosition(point);
226 if (d->existingStartPoint.isValid()) {
227 point = d->existingStartPoint.path->shapeToDocument(d->existingStartPoint.point->point());
230 d->activePoint = pathShape->
moveTo(point);
231 d->firstPoint = d->activePoint;
235 d->angleSnapStrategy =
new AngleSnapStrategy(d->angleSnappingDelta, d->angleSnapStatus);
241 d->dragStartPoint =
event->point;
243 if (d->angleSnapStrategy)
244 d->angleSnapStrategy->setStartPoint(d->activePoint->point());
250 return ((
bool) d->shape);
261 d->enableClosePathShortcut =
value;
281 d->hoveredPoint = d->endPointAtPosition(event->
point);
287 d->mouseOverFirstPoint =
false;
295 if (considerDrag && (event->
buttons() & Qt::LeftButton)) {
296 if (d->pointIsDragged ||
299 d->pointIsDragged =
true;
300 QPointF offset = snappedPosition - d->activePoint->point();
301 d->activePoint->setControlPoint2(d->activePoint->point() + offset);
303 if ((event->
modifiers() & Qt::AltModifier) == 0) {
304 d->activePoint->setControlPoint1(d->activePoint->point() - offset);
308 d->activePoint->setPoint(snappedPosition);
310 if (!d->prevPointWasDragged && d->autoSmoothCurves) {
312 if (index.second > 0) {
315 KoPathPoint *prevPoint = d->shape->pointByIndex(prevIndex);
320 if (index.second > 1) {
322 prevPrevPoint = d->shape->pointByIndex(prevPrevIndex);
326 const QPointF control1 = prevPoint->
point() + 0.3 * (prevPrevPoint->
point() - prevPoint->
point());
330 const QPointF control2 = prevPoint->
point() + 0.3 * (d->activePoint->point() - prevPoint->
point());
333 const QPointF activeControl = d->activePoint->point() + 0.3 * (prevPoint->
point() - d->activePoint->point());
334 d->activePoint->setControlPoint1(activeControl);
350 if (! d->shape || (event->
buttons() & Qt::RightButton))
return;
352 d->prevPointWasDragged = d->pointIsDragged;
353 d->pointIsDragged =
false;
356 if (!d->finishAfterThisPoint) {
357 d->activePoint = d->shape->lineTo(event->
point);
365 if (
qFuzzyCompare(diff1.x(), diff2.x()) && qFuzzyCompare(diff1.y(), diff2.y()))
369 if (d->finishAfterThisPoint) {
371 d->firstPoint->setControlPoint1(d->activePoint->controlPoint1());
372 delete d->shape->removePoint(d->shape->pathPointIndex(d->activePoint));
373 d->activePoint = d->firstPoint;
375 if (!d->prevPointWasDragged && d->autoSmoothCurves) {
379 d->shape->closeMerge();
382 d->existingStartPoint = 0;
388 d->angleSnapStrategy->deactivate();
413 delete d->shape->removePoint(d->shape->pathPointIndex(d->activePoint));
441 if (lastPointIndex.second > 1) {
442 lastPointIndex.second--;
443 delete d->shape->removePoint(lastPointIndex);
462 d->loadAutoSmoothValueFromConfig();
481 d->handleRadius = res.toUInt();
485 d->decorationThickness = res.toUInt();
502 d->existingStartPoint.validate(
canvas());
503 d->existingEndPoint.validate(
canvas());
505 if (d->connectPaths(pathShape, d->existingStartPoint, d->existingEndPoint)) {
506 if (d->existingStartPoint.isValid()) {
507 startShape = d->existingStartPoint.path;
509 if (d->existingEndPoint.isValid() && d->existingEndPoint != d->existingStartPoint) {
510 endShape = d->existingEndPoint.path;
514 if (tryMergeOnly && !startShape && !
endShape) {
561 QWidget *widget =
new QWidget();
562 widget->setObjectName(
"bezier-curve-tool-widget");
563 widget->setWindowTitle(i18n(
"Path options"));
565 QCheckBox *smoothCurves =
new QCheckBox(i18n(
"Autosmooth curve"), widget);
566 smoothCurves->setObjectName(
"smooth-curves-widget");
567 smoothCurves->setChecked(d->autoSmoothCurves);
569 QCheckBox *angleSnap =
new QCheckBox(i18n(
"Activate angle snap"), widget);
570 angleSnap->setObjectName(
"angle-snap-widget");
571 angleSnap->setChecked(
false);
572 angleSnap->setCheckable(
true);
575 angleEdit->setObjectName(
"angle-edit-widget");
576 angleEdit->
setAngle(d->angleSnappingDelta);
580 angleEdit->setEnabled(angleSnap->isChecked());
582 QHBoxLayout *angleEditLayout =
new QHBoxLayout;
583 angleEditLayout->setContentsMargins(10, 0, 0, 0);
584 angleEditLayout->setSpacing(0);
585 angleEditLayout->addWidget(angleEdit);
587 QVBoxLayout *mainLayout =
new QVBoxLayout;
588 mainLayout->setContentsMargins(0, 0, 0, 0);
589 mainLayout->setSpacing(5);
591 mainLayout->addWidget(smoothCurves);
592 mainLayout->addWidget(angleSnap);
593 mainLayout->addLayout(angleEditLayout);
595 widget->setLayout(mainLayout);
600 SIGNAL(toggled(
bool)),
602 SLOT(autoSmoothCurvesChanged(
bool)));
606 SLOT(setChecked(
bool)));
607 connect(angleEdit, SIGNAL(angleChanged(qreal)),
this, SLOT(angleDeltaChanged(qreal)));
610 SIGNAL(toggled(
bool)),
612 SLOT(setEnabled(
bool)));
618#include <moc_KoCreatePathTool.cpp>
float value(const T *src, size_t ch)
QPair< int, int > KoPathPointIndex
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
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 & highlightedPrimaryHandles()
static KisHandleStyle & primarySelection()
QPointer< KoShapeController > shapeController
virtual KoShapeManager * shapeManager() const =0
virtual void updateCanvas(const QRectF &rc)=0
virtual void addCommand(KUndo2Command *command)=0
QPointer< KoCanvasResourceProvider > resourceManager
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 setIgnoredPathPoints(const QList< KoPathPoint * > &ignoredPoints)
Sets a list of path points to ignore.
void paint(QPainter &painter, const KoViewConverter &converter)
paints the guide
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.