55#include <klocalizedstring.h>
57#include <QPainterPath>
66 qreal dx =
p1.x()-
p2.x();
67 qreal dy =
p1.y()-
p2.y();
88 , m_pointSelection(this)
108 m_selectCursor = QCursor(QIcon(
":/cursor-needle.svg").pixmap(32), 0, 0);
109 m_moveCursor = QCursor(QIcon(
":/cursor-needle-move.svg").pixmap(32), 0, 0);
127 toolOptions->setWindowTitle(i18n(
"Edit Shape"));
128 list.append(toolOptions);
153 if (initialConversionCommand) {
154 initialConversionCommand->
redo();
160 if (initialConversionCommand) {
163 parent->setText(command->
text());
165 parent->addCommand(command);
169 d->canvas->addCommand(command);
177 if (segments.size() == 1) {
178 qreal positionInSegment = 0.5;
184 d->canvas->addCommand(cmd);
205 d->canvas->addCommand(cmd);
217 for (; it != selectedPoints.constEnd(); ++it) {
218 KoPathPoint *point = it->pathShape->pointByIndex(it->pointIndex);
220 pointToChange.append(*it);
223 if (! pointToChange.isEmpty()) {
238 d->canvas->addCommand(command);
249 for (; it != points.constEnd(); ++it) {
250 KoPathPoint *point = it->pathShape->pointByIndex(it->pointIndex);
252 pointToChange.append(*it);
255 if (!pointToChange.isEmpty()) {
267 if (segments.size() > 0) {
278 if (segments.size() > 0) {
295 parameterShapes.append(parametric);
299 if (!parameterShapes.isEmpty()) {
306 textShapes.append(text);
310 if (!textShapes.isEmpty()) {
312 const QList<KoShape*> oldSelectedShapes = implicitCastList<KoShape*>(textShapes);
325 newSelectedShapes << outlineShape;
353 if (index1.second != 0 && index1.second != path1->
subpathPointCount(index1.first)-1)
357 if (index2.second != 0 && index2.second != path2->
subpathPointCount(index2.first)-1)
372 if (pointData.size() != 2)
return;
377 if (!checkCanJoinToPoints(pd1, pd2)) {
386 cmd =
new KoMultiPathPointJoinCommand(pd1, pd2, d->canvas->shapeController()->documentBase(), d->canvas->shapeManager()->selection());
390 d->canvas->addCommand(cmd);
417 if (segments.size() == 1) {
431 if (segments.size() == 1) {
453 if (!shape->
stroke() || !shape->
stroke()->isVisible()) {
503 d->canvas->snapGuide()->paint(painter, converter);
512 QRectF newDecorationsRect;
536 return newDecorationsRect;
551 if (event->
button() & Qt::LeftButton) {
571 if (shape && !
selection->isSelected(shape)) {
573 if (!(event->
modifiers() & Qt::ShiftModifier)) {
589 if (event->
button() & Qt::RightButton)
610 int handleId = parameterShape->
handleIdAt(roi);
611 if (handleId != -1) {
621 if (! points.empty()) {
625 qreal minDistance = HUGE_VAL;
633 if (
p->activeControlPoint1() && roi.contains(
p->controlPoint1())) {
635 if (dist < minDistance) {
642 if (
p->activeControlPoint2() && roi.contains(
p->controlPoint2())) {
644 if (dist < minDistance) {
653 if (dist < minDistance) {
667 Q_EMIT
statusTextChanged(i18n(
"Drag to move point. Shift click to change point type."));
692 Q_EMIT
statusTextChanged(i18n(
"Drag to change curve directly. Double click to insert new path point."));
697 if (selectedPointCount == 0)
701 if (selectedPointCount == 1)
720 d->canvas->addCommand(command);
734 switch (event->key()) {
735 case Qt::Key_Control:
739 if (! event->isAutoRepeat()) {
752 switch (event->key()) {
773 switch (event->key()) {
774 case Qt::Key_Control:
778 if (! event->isAutoRepeat()) {
802 d->canvas->addCommand(cmd);
820 QScopedPointer<PathSegment> segment(
new PathSegment);
832 qreal minDistance = std::numeric_limits<qreal>::max();
839 const QPointF nearestPoint = s.
pointAt(nearestPointParam);
847 segment->path = shape;
848 segment->segmentStart = s.
first();
849 segment->positionOnSegment = nearestPointParam;
854 if (!segment->isValid()) {
858 return segment.take();
867 d->canvas->snapGuide()->reset();
900 d->canvas->selectedShapesProxy()->selection()->selectedEditableShapesAndDelegates();
926 Q_FOREACH (
KoShape *shape, shapes) {
930 selectedShapes.append(pathShape);
946 PathToolOptionWidget::Types type;
962 bool canBreakAtPoint =
false;
964 bool hasNonSmoothPoints =
false;
965 bool hasNonSymmetricPoints =
false;
966 bool hasNonSplitPoints =
false;
968 bool hasNonLinePoints =
false;
969 bool hasNonCurvePoints =
false;
971 bool canJoinSubpaths =
false;
973 if (!pointData.isEmpty()) {
993 if (pointData.size() == 2) {
997 canJoinSubpaths = checkCanJoinToPoints(pd1, pd2);
1018 bool canSplitAtSegment =
false;
1019 bool canConvertSegmentToLine =
false;
1020 bool canConvertSegmentToCurve=
false;
1022 if (!segments.isEmpty()) {
1024 canSplitAtSegment = segments.size() == 1;
1026 bool hasLines =
false;
1027 bool hasCurves =
false;
1031 hasLines |= segment.
degree() == 1;
1032 hasCurves |= segment.
degree() > 1;
1035 canConvertSegmentToLine = !segments.isEmpty() && hasCurves;
1036 canConvertSegmentToCurve= !segments.isEmpty() && hasLines;
1048 bool haveConvertibleShapes =
false;
1055 haveConvertibleShapes =
true;
1073 d->canvas->snapGuide()->reset();
1111void addActionsGroupIfEnabled(QMenu *menu, QAction *a1, QAction *a2)
1113 if (a1->isEnabled() || a2->isEnabled()) {
1114 menu->addAction(a1);
1115 menu->addAction(a2);
1116 menu->addSeparator();
1120void addActionsGroupIfEnabled(QMenu *menu, QAction *a1, QAction *a2, QAction *a3)
1122 if (a1->isEnabled() || a2->isEnabled()) {
1123 menu->addAction(a1);
1124 menu->addAction(a2);
1125 menu->addAction(a3);
1126 menu->addSeparator();
qreal distance(const QPointF &p1, const QPointF &p2)
QPair< int, int > KoPathPointIndex
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
KUndo2MagicString text() const
The KisHandlePainterHelper class is a special helper for painting handles around objects....
void drawPath(const QPainterPath &path)
void setHandleStyle(const KisHandleStyle &style)
static KisHandleStyle & secondarySelection()
static KisHandleStyle & primarySelection()
void addConnection(Sender sender, Signal signal, Receiver receiver, Method method, Qt::ConnectionType type=Qt::AutoConnection)
QPointer< KoShapeController > shapeController
virtual KoShapeManager * shapeManager() const =0
virtual void addCommand(KUndo2Command *command)=0
virtual KoSelectedShapesProxy * selectedShapesProxy() const =0
selectedShapesProxy() is a special interface for keeping a persistent connections to selectionChanged...
void paintHandles(KisHandlePainterHelper &handlesHelper)
Paint the handles.
bool isParametricShape() const
Check if object is a parametric shape.
int handleIdAt(const QRectF &rect) const
Get the id of the handle within the given rect.
The undo / redo command for changing a KoParameterShape into a KoPathShape.
Command to break a subpath at points.
Describe a KoPathPoint by a KoPathShape and its indices.
KoPathPointIndex pointIndex
position of the point in the path shape
KoPathShape * pathShape
path shape the path point belongs too
The undo / redo command for inserting path points.
QList< KoPathPoint * > insertedPoints() const
Returns list of inserted points.
static KUndo2Command * createCommand(const QList< KoPathPointData > &pointDataList, KoShapeController *shapeController, KUndo2Command *parent=0)
Create command for removing points from path shapes.
Strategy to rubber select points of a path shape.
The undo / redo command for changing the path point type.
PointType
The type of the point.
A KoPathPoint represents a point in a path.
PointProperties properties
QRectF boundingRect(bool active=true) const
Get the bounding rect of the point.
@ IsSmooth
it is smooth, both control points on a line through the point
@ IsSymmetric
it is symmetric, like smooth but control points have same distance to point
PointType
the type for identifying part of a KoPathPoint
@ ControlPoint2
the second control point
@ ControlPoint1
the first control point
The undo / redo command for breaking a subpath by removing the segment.
Strategy for deforming a segment of a path shape.
The undo / redo command for changing segments to curves/lines.
A KoPathSegment consist of two neighboring KoPathPoints.
int degree() const
Returns the degree of the segment: 1 = line, 2 = quadratic, 3 = cubic, -1 = invalid.
QPointF pointAt(qreal t) const
Returns point at given t.
qreal nearestPoint(const QPointF &point) const
bool isValid() const
Returns if segment is valid, e.g. has two valid points.
QRectF boundingRect() const
Returns the axis aligned tight bounding rect.
KoPathSegment toCubic() const
Returns cubic bezier curve segment of this segment.
The position of a path point within a path shape.
int subpathPointCount(int subpathIndex) const
Returns the number of points in a subpath.
bool isClosedSubpath(int subpathIndex) const
Checks if a subpath is closed.
QList< KoPathPoint * > pointsAt(const QRectF &rect, const bool useControlPoints=false) const
Returns the path points within the given rectangle.
QList< KoPathSegment > segmentsAt(const QRectF &rect) const
Returns the list of path segments within the given rectangle.
QPainterPath outline() const override
reimplemented
KoPathSegment segmentByIndex(const KoPathPointIndex &pointIndex) const
Returns the segment specified by a path point index.
virtual void paintPoints(KisHandlePainterHelper &handlesHelper)
KoPathPointIndex pathPointIndex(const KoPathPoint *point) const
Returns the path point index of a given path point.
KoPathPoint * pointByIndex(const KoPathPointIndex &pointIndex) const
Returns the path point specified by a path point index.
Qt::MouseButton button() const
return button pressed (see QMouseEvent::button());
Qt::KeyboardModifiers modifiers() const
QPointF point
The point in document coordinates.
virtual KoSelection * selection()=0
void connectToCanvas(KoCanvasBase *canvas)
KoShape * shapeAt(const QPointF &position, KoFlake::ShapeSelection selection=KoFlake::ShapeOnTop, bool omitHiddenShapes=true)
virtual bool isShapeEditable(bool recursive=true) const
checks recursively if the shape or one of its parents is not visible or locked
virtual KoShapeStrokeModelSP stroke() const
QPointF documentToShape(const QPointF &point) const
Transforms point from document coordinates to shape coordinates.
virtual QRectF boundingRect() const
Get the bounding box of the shape.
KoShapeContainer * parent() const
static KisHandlePainterHelper createHandlePainterHelperView(QPainter *painter, KoShape *shape, const KoViewConverter &converter, qreal handleRadius=0.0, int decorationThickness=1)
KoShape * textOutline() const
textOutline This turns the text object into non-text KoShape(s) to the best of its abilities.
virtual QPointF documentToView(const QPointF &documentPoint) const
KoPathPoint * activePoint() const
KoPathPoint::PointType activePointType() const
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
#define KIS_ASSERT_RECOVER_RETURN(cond)
qreal kisDistance(const QPointF &pt1, const QPointF &pt2)
T kisGrowRect(const T &rect, U offset)
KUndo2MagicString kundo2_i18n(const char *text)
auto maxDimension(Size size) -> decltype(size.width())
@ 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.
@ ShapeOnTop
return the shape highest z-ordering, regardless of selection.