67#include <QPainterPath>
72#include <QActionGroup>
88#define HANDLE_DISTANCE 10
89#define HANDLE_DISTANCE_SQ (HANDLE_DISTANCE * HANDLE_DISTANCE)
91#define INNER_HANDLE_DISTANCE_SQ 16
94static const QString EditFillGradientFactoryId =
"edit_fill_gradient";
95static const QString EditStrokeGradientFactoryId =
"edit_stroke_gradient";
96static const QString EditFillMeshGradientFactoryId =
"edit_fill_meshgradient";
98enum TransformActionType {
100 TransformRotate90CCW,
134 Q_UNUSED(displayRendererInterface)
155 void finishInteraction(Qt::KeyboardModifiers modifiers = QFlags<Qt::KeyboardModifier>())
override
169 Q_FOREACH (
KoShape * shape, shapes) {
217 Q_UNUSED(displayRendererInterface)
237 if (shapes.size() == 1) {
238 shape = shapes.first();
250 const qreal distanceThresholdSq =
256 qreal minDistanceSq = std::numeric_limits<qreal>::max();
264 if (distanceSq < distanceThresholdSq && distanceSq < minDistanceSq) {
266 minDistanceSq = distanceSq;
337 Q_UNUSED(displayRendererInterface);
359 if (shapes.size() == 1) {
360 shape = shapes.first();
374 const qreal distanceThresholdSq =
380 qreal minDistanceSq = std::numeric_limits<qreal>::max();
384 for (
const auto& handle: sh.
handles()) {
385 const QPointF handlePoint = converter->
documentToView(handle.pos);
388 if (distanceSq < distanceThresholdSq && distanceSq < minDistanceSq) {
390 minDistanceSq = distanceSq;
428 , m_hotPosition(
KoFlake::TopLeft)
429 , m_mouseWasInsideHandles(false)
432 , m_tabbedOptionWidget(0)
437 QPixmap rotatePixmap, shearPixmap;
438 rotatePixmap = QIcon(
":/cursor_rotate.svg").pixmap(22, 22);
439 Q_ASSERT(!rotatePixmap.isNull());
440 shearPixmap = QIcon(
":/cursor_shear.svg").pixmap(22, 22);
441 Q_ASSERT(!shearPixmap.isNull());
443 m_rotateCursors[0] = QCursor(rotatePixmap.transformed(QTransform().rotate(45)));
444 m_rotateCursors[1] = QCursor(rotatePixmap.transformed(QTransform().rotate(90)));
445 m_rotateCursors[2] = QCursor(rotatePixmap.transformed(QTransform().rotate(135)));
446 m_rotateCursors[3] = QCursor(rotatePixmap.transformed(QTransform().rotate(180)));
447 m_rotateCursors[4] = QCursor(rotatePixmap.transformed(QTransform().rotate(225)));
448 m_rotateCursors[5] = QCursor(rotatePixmap.transformed(QTransform().rotate(270)));
449 m_rotateCursors[6] = QCursor(rotatePixmap.transformed(QTransform().rotate(315)));
462 m_shearCursors[1] = QCursor(shearPixmap.transformed(QTransform().rotate(45)));
463 m_shearCursors[2] = QCursor(shearPixmap.transformed(QTransform().rotate(90)));
464 m_shearCursors[3] = QCursor(shearPixmap.transformed(QTransform().rotate(135)));
465 m_shearCursors[4] = QCursor(shearPixmap.transformed(QTransform().rotate(180)));
466 m_shearCursors[5] = QCursor(shearPixmap.transformed(QTransform().rotate(225)));
467 m_shearCursors[6] = QCursor(shearPixmap.transformed(QTransform().rotate(270)));
468 m_shearCursors[7] = QCursor(shearPixmap.transformed(QTransform().rotate(315)));
478 if (connectToSelectedShapesProxy) {
499 1, EditFillGradientFactoryId,
this));
511 0, EditStrokeGradientFactoryId,
this));
525 EditFillMeshGradientFactoryId,
this));
542 if (shapes.isEmpty())
return;
546 bool convertableShape =
false;
548 Q_FOREACH(
KoShape *shape, shapes) {
550 if (textShape && textShape->
textType() != type) {
552 if (!convertableShape) {
553 convertableShape =
true;
561 if (convertableShape) {
575 if (selectedShapes.isEmpty())
return;
577 Q_FOREACH(
KoShape *shape, selectedShapes) {
580 if (text && !textShape) {
582 }
else if (path && path->isClosedSubpath(0)) {
583 shapes.append(shape);
586 if (!textShape)
return;
587 if (shapes.isEmpty())
return;
597 Q_FOREACH(
KoShape *shape, shapes) {
616 if (selectedShapes.isEmpty())
return;
618 Q_FOREACH(
KoShape *shape, selectedShapes) {
620 if (text && !textShape) {
625 if (textShape && textPath) {
629 if (!(textShape && textPath))
return;
677 if (selectedShapes.isEmpty())
return;
679 Q_FOREACH(
KoShape *shape, selectedShapes) {
682 if (text && !textShape) {
684 }
else if (path && path->isClosedSubpath(0)) {
685 shapes.append(shape);
688 if (!textShape)
return;
689 if (shapes.isEmpty())
return;
699 Q_FOREACH(
KoShape *shape, shapes) {
717 if (!textShape)
return;
722 if (selectedShapes.isEmpty())
return;
727 Q_FOREACH(
KoShape *shape, selectedShapes) {
739 if (!textShape)
return;
744 if (selectedShapes.isEmpty())
return;
747 bool addToCanvas =
false;
748 Q_FOREACH(
KoShape *shape, selectedShapes) {
762 if (!textShape)
return;
767 if (selectedShapes.isEmpty())
return;
781 Q_FOREACH(
KoShape *shape, selectedShapes) {
782 if (!textShape->
shapesInside().contains(shape))
continue;
783 shapesInside.append(shape);
786 if (!shapesInside.isEmpty()) {
804 QAction *a =
action(actionId);
805 connect(a, SIGNAL(triggered()), mapper, SLOT(map()));
852 if (!
action(
"text_type_preformatted")->actionGroup()) {
853 QActionGroup *textTypeActions =
new QActionGroup(
this);
854 textTypeActions->addAction(
action(
"text_type_preformatted"));
855 textTypeActions->addAction(
action(
"text_type_inline_wrap"));
856 textTypeActions->addAction(
action(
"text_type_pre_positioned"));
857 textTypeActions->setExclusive(
false);
858 Q_FOREACH (QAction *a, textTypeActions->actions()) {
859 a->setCheckable(
false);
880 if (useEdgeRotation) {
886 direction = handlePosition - selectionCenter;
893 if (useEdgeRotation) {
899 direction = handlePosition - selectionCenter;
906 if (useEdgeRotation) {
912 direction = handlePosition - selectionCenter;
920 if (useEdgeRotation) {
926 direction = handlePosition - selectionCenter;
938 qreal rotation = atan2(direction.y(), direction.x()) * 180.0 /
M_PI;
942 if (useEdgeRotation) {
952 if (useEdgeRotation) {
962 if (useEdgeRotation) {
972 if (useEdgeRotation) {
985 if (rotation < 0.0) {
996 QCursor
cursor = Qt::ArrowCursor;
1002 bool editable = !
selection->selectedEditableShapes().isEmpty();
1006 int rotOctant = 8 + int(8.5 +
m_angle / 45);
1008 bool rotateHandle =
false;
1009 bool shearHandle =
false;
1017 rotateHandle =
true;
1025 rotateHandle =
true;
1033 rotateHandle =
true;
1041 rotateHandle =
true;
1044 cursor = Qt::ArrowCursor;
1048 statusText = i18n(
"Left click rotates around center, right click around highlighted position.");
1051 statusText = i18n(
"Click and drag to shear selection.");
1056 statusText = i18n(
"Click and drag to resize selection.");
1058 int rotOctant = 8 + int(8.5 +
m_angle / 45);
1059 bool cornerHandle =
false;
1066 cornerHandle =
true;
1073 cornerHandle =
true;
1080 cornerHandle =
true;
1087 cornerHandle =
true;
1090 cursor = Qt::SizeAllCursor;
1091 statusText = i18n(
"Click and drag to move selection.");
1095 statusText = i18n(
"Click and drag to resize selection. Middle click to set highlighted position.");
1099 cursor = Qt::ArrowCursor;
1124 const bool isSelectionMask = node && node->inherits(
"KisSelectionMask");
1171 i18n(
"This tool only works on vector layers. You probably want the move tool."),
1193 if (bound.contains(event->
point)) {
1230 bound.adjust(-border.x(), -border.y(), border.x(), border.y());
1247 if (!(event->
modifiers() & Qt::ShiftModifier)) {
1259 bool result =
false;
1261 qreal x = 0.0, y = 0.0;
1262 if (direction == Qt::Key_Left) {
1264 }
else if (direction == Qt::Key_Right) {
1266 }
else if (direction == Qt::Key_Up) {
1268 }
else if (direction == Qt::Key_Down) {
1272 if (x != 0.0 || y != 0.0) {
1274 if ((modifiers & Qt::ShiftModifier) != 0) {
1277 }
else if ((modifiers & Qt::AltModifier) != 0) {
1284 if (!shapes.isEmpty()) {
1297 switch (event->key()) {
1336 if (!shapes.isEmpty()) {
1352 if (!shapes.empty()) {
1366 Q_ASSERT(
canvas()->selectedShapesProxy());
1379 Q_ASSERT(
canvas()->selectedShapesProxy());
1387 Q_ASSERT(
canvas()->selectedShapesProxy());
1415 if (innerHandleMeaning) {
1418 *innerHandleMeaning = path.contains(point) || path.intersects(
handlePaintRect(point));
1432 if (innerHandleMeaning) {
1434 *innerHandleMeaning =
true;
1448 QTransform matrix =
selection->absoluteTransformation();
1465 if (s->scaleX() < 0) {
1470 if (s->scaleY() < 0) {
1483 QAction *actionBringToFront =
action(
"object_order_front");
1484 connect(actionBringToFront, SIGNAL(triggered()),
this, SLOT(
selectionBringToFront()), Qt::UniqueConnection);
1486 QAction *actionRaise =
action(
"object_order_raise");
1487 connect(actionRaise, SIGNAL(triggered()),
this, SLOT(
selectionMoveUp()), Qt::UniqueConnection);
1489 QAction *actionLower =
action(
"object_order_lower");
1492 QAction *actionSendToBack =
action(
"object_order_back");
1493 connect(actionSendToBack, SIGNAL(triggered()),
this, SLOT(
selectionSendToBack()), Qt::UniqueConnection);
1495 QAction *actionGroupBottom =
action(
"object_group");
1496 connect(actionGroupBottom, SIGNAL(triggered()),
this, SLOT(
selectionGroup()), Qt::UniqueConnection);
1498 QAction *actionUngroupBottom =
action(
"object_ungroup");
1499 connect(actionUngroupBottom, SIGNAL(triggered()),
this, SLOT(
selectionUngroup()), Qt::UniqueConnection);
1501 QAction *actionSplit =
action(
"object_split");
1502 connect(actionSplit, SIGNAL(triggered()),
this, SLOT(
selectionSplitShapes()), Qt::UniqueConnection);
1511 QAction *actionTextInside =
action(
"add_shape_to_flow_area");
1512 connect(actionTextInside, SIGNAL(triggered()),
this, SLOT(
slotAddShapesToFlow()), Qt::UniqueConnection);
1514 QAction *actionTextSubtract =
action(
"subtract_shape_from_flow_area");
1517 QAction *actionTextOnPath =
action(
"put_text_on_path");
1518 connect(actionTextOnPath, SIGNAL(triggered()),
this, SLOT(
slotPutTextOnPath()), Qt::UniqueConnection);
1520 QAction *actionTextRemoveFlow =
action(
"remove_shapes_from_text_flow");
1523 QAction *actionTextFlowToggle =
action(
"flow_shape_type_toggle");
1524 connect(actionTextFlowToggle, SIGNAL(triggered()),
this, SLOT(
slotToggleFlowShapeType()), Qt::UniqueConnection);
1532 const KisCanvas2 *canvas2 = qobject_cast<const KisCanvas2 *>(this->
canvas());
1547 QAction *actionBringToFront =
action(
"object_order_front");
1548 disconnect(actionBringToFront, 0,
this, 0);
1550 QAction *actionRaise =
action(
"object_order_raise");
1551 disconnect(actionRaise, 0,
this, 0);
1553 QAction *actionLower =
action(
"object_order_lower");
1554 disconnect(actionLower, 0,
this, 0);
1556 QAction *actionSendToBack =
action(
"object_order_back");
1557 disconnect(actionSendToBack, 0,
this, 0);
1559 QAction *actionGroupBottom =
action(
"object_group");
1560 disconnect(actionGroupBottom, 0,
this, 0);
1562 QAction *actionUngroupBottom =
action(
"object_ungroup");
1563 disconnect(actionUngroupBottom, 0,
this, 0);
1565 QAction *actionSplit =
action(
"object_split");
1566 disconnect(actionSplit, 0,
this, 0);
1575 QAction *actionTextInside =
action(
"add_shape_to_flow_area");
1576 disconnect(actionTextInside, 0,
this, 0);
1577 QAction *actionTextSubtract =
action(
"subtract_shape_from_flow_area");
1578 disconnect(actionTextSubtract, 0,
this, 0);
1579 QAction *actionTextOnPath =
action(
"put_text_on_path");
1580 disconnect(actionTextOnPath, 0,
this, 0);
1581 QAction *actionTextRemoveFlow =
action(
"remove_shapes_from_text_flow");
1582 disconnect(actionTextRemoveFlow, 0,
this, 0);
1583 QAction *actionTextFlowToggle =
action(
"flow_shape_type_toggle");
1584 disconnect(actionTextFlowToggle, 0,
this, 0);
1586 const KisCanvas2 *canvas2 = qobject_cast<const KisCanvas2 *>(this->
canvas());
1604 if (selectedShapes.isEmpty())
return;
1606 const int groupZIndex = selectedShapes.last()->zIndex();
1635 Q_FOREACH (
KoShape *shape, selectedShapes) {
1642 newShapes << group->
shapes();
1661 if (editableShapes.isEmpty()) {
1665 QTransform applyTransform;
1666 bool shouldReset =
false;
1670 switch (TransformActionType(transformAction)) {
1671 case TransformRotate90CW:
1672 applyTransform.rotate(90.0);
1673 actionName =
kundo2_i18n(
"Rotate Object 90° CW");
1675 case TransformRotate90CCW:
1676 applyTransform.rotate(-90.0);
1677 actionName =
kundo2_i18n(
"Rotate Object 90° CCW");
1679 case TransformRotate180:
1680 applyTransform.rotate(180.0);
1683 case TransformMirrorX:
1684 applyTransform.scale(-1.0, 1.0);
1685 actionName =
kundo2_i18n(
"Mirror Object Horizontally");
1687 case TransformMirrorY:
1688 applyTransform.scale(1.0, -1.0);
1689 actionName =
kundo2_i18n(
"Mirror Object Vertically");
1691 case TransformReset:
1693 actionName =
kundo2_i18n(
"Reset Object Transformations");
1697 if (!shouldReset && applyTransform.isIdentity())
return;
1703 const QPointF centerPoint = outlineRect.center();
1704 const QTransform centerTrans = QTransform::fromTranslate(centerPoint.x(), centerPoint.y());
1705 const QTransform centerTransInv = QTransform::fromTranslate(-centerPoint.x(), -centerPoint.y());
1711 Q_FOREACH (
KoShape *shape, transformedShapes) {
1718 t = world * centerTransInv * applyTransform * centerTrans * world.inverted() * shape->
transformation();
1720 const QPointF center = shape->
outlineRect().center();
1721 const QPointF offset = shape->
transformation().map(center) - center;
1722 t = QTransform::fromTranslate(offset.x(), offset.y());
1725 newTransforms.append(t);
1739 if (editableShapes.isEmpty()) {
1744 QPainterPath dstOutline;
1748 const int referenceShapeIndex = 0;
1749 KoShape *referenceShape = editableShapes[referenceShapeIndex];
1753 const QTransform booleanWorkaroundTransform =
1756 Q_FOREACH (
KoShape *shape, editableShapes) {
1758 booleanWorkaroundTransform.map(
1763 if (booleanOp == BooleanUnion) {
1764 Q_FOREACH (
const QPainterPath &path, srcOutlines) {
1768 }
else if (booleanOp == BooleanIntersection) {
1769 for (
int i = 0; i < srcOutlines.size(); i++) {
1771 dstOutline = srcOutlines[i];
1773 dstOutline &= srcOutlines[i];
1779 dstOutline.closeSubpath();
1783 }
else if (booleanOp == BooleanSubtraction) {
1784 for (
int i = 0; i < srcOutlines.size(); i++) {
1785 dstOutline = srcOutlines[referenceShapeIndex];
1786 if (i != referenceShapeIndex) {
1787 dstOutline -= srcOutlines[i];
1794 dstOutline = booleanWorkaroundTransform.inverted().map(dstOutline);
1798 if (!dstOutline.isEmpty()) {
1816 newSelectedShapes << newShape;
1832 if (editableShapes.isEmpty()) {
1841 Q_FOREACH (
KoShape *shape, editableShapes) {
1843 if (!pathShape)
return;
1846 if (pathShape->
separate(splitShapes)) {
1847 QList<KoShape*> normalShapes = implicitCastList<KoShape*>(splitShapes);
1852 newShapes << normalShapes;
1870 if (editableShapes.isEmpty()) {
1880 if (editableShapes.count() == 1) {
1902 if (editableShapes.size() < 3) {
1939 if (selectedShapes.isEmpty()) {
1961 SIGNAL(sigSwitchModeEditFillGradient(
bool)),
1965 SIGNAL(sigSwitchModeEditStrokeGradient(
bool)),
1969 SIGNAL(sigSwitchModeEditFillGradient(
bool)),
1974 SIGNAL(sigMeshGradientResetted()),
1993 bool insideSelection =
false;
1996 bool editableShape = !
selection->selectedEditableShapes().isEmpty();
1998 const bool selectMultiple =
event->modifiers() & Qt::ShiftModifier;
1999 const bool selectNextInStack =
event->modifiers() & Qt::ControlModifier;
2000 const bool avoidSelection =
event->modifiers() & Qt::AltModifier;
2002 if (selectNextInStack) {
2052 if (!avoidSelection && editableShape) {
2056 if (insideSelection) {
2075 if (!selectMultiple && !selectNextInStack) {
2077 if (insideSelection) {
2086 if (!selectMultiple) {
2093 if (selectMultiple) {
2097 if (!selectMultiple) {
2118 const bool hasEditableShapes = !editableShapes.isEmpty();
2120 action(
"object_order_front")->setEnabled(hasEditableShapes);
2121 action(
"object_order_raise")->setEnabled(hasEditableShapes);
2122 action(
"object_order_lower")->setEnabled(hasEditableShapes);
2123 action(
"object_order_back")->setEnabled(hasEditableShapes);
2125 action(
"object_transform_rotate_90_cw")->setEnabled(hasEditableShapes);
2126 action(
"object_transform_rotate_90_ccw")->setEnabled(hasEditableShapes);
2127 action(
"object_transform_rotate_180")->setEnabled(hasEditableShapes);
2128 action(
"object_transform_mirror_horizontally")->setEnabled(hasEditableShapes);
2129 action(
"object_transform_mirror_vertically")->setEnabled(hasEditableShapes);
2130 action(
"object_transform_reset")->setEnabled(hasEditableShapes);
2132 const bool multipleSelected = editableShapes.size() > 1;
2134 const bool alignmentEnabled =
2136 (!editableShapes.isEmpty() &&
2139 action(
"object_align_horizontal_left")->setEnabled(alignmentEnabled);
2140 action(
"object_align_horizontal_center")->setEnabled(alignmentEnabled);
2141 action(
"object_align_horizontal_right")->setEnabled(alignmentEnabled);
2142 action(
"object_align_vertical_top")->setEnabled(alignmentEnabled);
2143 action(
"object_align_vertical_center")->setEnabled(alignmentEnabled);
2144 action(
"object_align_vertical_bottom")->setEnabled(alignmentEnabled);
2146 const bool distributionEnabled = editableShapes.size() > 2;
2148 action(
"object_distribute_horizontal_left")->setEnabled(distributionEnabled);
2149 action(
"object_distribute_horizontal_center")->setEnabled(distributionEnabled);
2150 action(
"object_distribute_horizontal_right")->setEnabled(distributionEnabled);
2151 action(
"object_distribute_horizontal_gaps")->setEnabled(distributionEnabled);
2153 action(
"object_distribute_vertical_top")->setEnabled(distributionEnabled);
2154 action(
"object_distribute_vertical_center")->setEnabled(distributionEnabled);
2155 action(
"object_distribute_vertical_bottom")->setEnabled(distributionEnabled);
2156 action(
"object_distribute_vertical_gaps")->setEnabled(distributionEnabled);
2159 bool textShape =
false;
2160 bool otherShapes =
false;
2161 bool filledShapes =
false;
2162 bool shapesInside =
false;
2164 const bool editFlowShapes = bool(currentTextShapeGroup);
2165 Q_FOREACH(
KoShape *shape, editableShapes) {
2167 if (text && !textShape) {
2172 filledShapes = filledShapes? filledShapes: (path && path->isClosedSubpath(0));
2173 if (editFlowShapes) {
2174 if (!shapesInside && currentTextShapeGroup->
shapesInside().contains(shape)) {
2175 shapesInside =
true;
2179 if (textShape && otherShapes)
break;
2181 const bool editContours = textShape && otherShapes;
2182 const bool editFilledContours = textShape && filledShapes;
2184 action(
"add_shape_to_flow_area")->setEnabled(editFilledContours);
2185 action(
"subtract_shape_from_flow_area")->setEnabled(editFilledContours);
2186 action(
"put_text_on_path")->setEnabled(editContours);
2187 action(
"remove_shapes_from_text_flow")->setEnabled(editFlowShapes);
2188 action(
"flow_shape_type_toggle")->setEnabled(editFlowShapes);
2189 action(
"flow_shape_order_back")->setEnabled(shapesInside);
2190 action(
"flow_shape_order_earlier")->setEnabled(shapesInside);
2191 action(
"flow_shape_order_later")->setEnabled(shapesInside);
2192 action(
"flow_shape_order_front")->setEnabled(shapesInside);
2200 const bool multipleSelected = editableShapes.size() > 1;
2202 action(
"object_group")->setEnabled(multipleSelected);
2204 action(
"object_unite")->setEnabled(multipleSelected);
2205 action(
"object_intersect")->setEnabled(multipleSelected);
2206 action(
"object_subtract")->setEnabled(multipleSelected);
2208 bool hasShapesWithMultipleSegments =
false;
2209 Q_FOREACH (
KoShape *shape, editableShapes) {
2212 hasShapesWithMultipleSegments =
true;
2216 action(
"object_split")->setEnabled(hasShapesWithMultipleSegments);
2219 bool hasGroupShape =
false;
2220 foreach (
KoShape *shape, editableShapes) {
2222 hasGroupShape =
true;
2226 action(
"object_ungroup")->setEnabled(hasGroupShape);
2228 bool enablePreformatted =
false;
2229 bool enablePrePositioned =
false;
2230 bool enableInlineWrapped =
false;
2232 Q_FOREACH (
KoShape *shape, editableShapes) {
2237 enablePreformatted =
true;
2240 enablePrePositioned =
true;
2243 enableInlineWrapped =
true;
2247 QActionGroup *group =
action(
"text_type_preformatted")->actionGroup();
2249 group->setEnabled(text);
2252 action(
"text_type_preformatted")->setEnabled(enablePreformatted);
2253 action(
"text_type_pre_positioned")->setEnabled(enablePrePositioned);
2254 action(
"text_type_inline_wrap")->setEnabled(enableInlineWrapped);
2271 QMenu *transform =
m_contextMenu->addMenu(i18n(
"Transform"));
2273 transform->addAction(
action(
"object_transform_rotate_90_cw"));
2274 transform->addAction(
action(
"object_transform_rotate_90_ccw"));
2275 transform->addAction(
action(
"object_transform_rotate_180"));
2276 transform->addSeparator();
2277 transform->addAction(
action(
"object_transform_mirror_horizontally"));
2278 transform->addAction(
action(
"object_transform_mirror_vertically"));
2279 transform->addSeparator();
2280 transform->addAction(
action(
"object_transform_reset"));
2282 if (
action(
"object_unite")->isEnabled() ||
2283 action(
"object_intersect")->isEnabled() ||
2284 action(
"object_subtract")->isEnabled() ||
2285 action(
"object_split")->isEnabled()) {
2287 QMenu *transform =
m_contextMenu->addMenu(i18n(
"Logical Operations"));
2288 transform->addAction(
action(
"object_unite"));
2289 transform->addAction(
action(
"object_intersect"));
2290 transform->addAction(
action(
"object_subtract"));
2291 transform->addAction(
action(
"object_split"));
2308 if (
action(
"object_group")->isEnabled() ||
action(
"object_ungroup")->isEnabled()) {
2318 text->addAction(
action(
"add_shape_to_flow_area"));
2319 text->addAction(
action(
"subtract_shape_from_flow_area"));
2320 text->addAction(
action(
"put_text_on_path"));
2321 text->addSeparator();
2322 text->addAction(
action(
"text_type_preformatted"));
2323 text->addAction(
action(
"text_type_inline_wrap"));
2324 text->addAction(
action(
"text_type_pre_positioned"));
2325 text->addSeparator();
2326 text->addAction(
action(
"remove_shapes_from_text_flow"));
2327 text->addAction(
action(
"flow_shape_type_toggle"));
2328 text->addSeparator();
2329 text->addAction(
action(
"flow_shape_order_back"));
2330 text->addAction(
action(
"flow_shape_order_earlier"));
2331 text->addAction(
action(
"flow_shape_order_later"));
2332 text->addAction(
action(
"flow_shape_order_front"));
2339 menu->addAction(
action(
"object_transform_rotate_90_cw"));
2340 menu->addAction(
action(
"object_transform_rotate_90_ccw"));
2341 menu->addAction(
action(
"object_transform_rotate_180"));
2342 menu->addSeparator();
2343 menu->addAction(
action(
"object_transform_mirror_horizontally"));
2344 menu->addAction(
action(
"object_transform_mirror_vertically"));
2345 menu->addSeparator();
2346 menu->addAction(
action(
"object_transform_reset"));
2353 QTimer::singleShot(0, [tool = std::move(tool)]() {
2384 if (!
d->parent->selection()->hasSelection())
return props;
2387 for (
auto it =
shapes.begin(); it !=
shapes.end(); it++) {
2389 if (!textShape)
continue;
2409 if (
d->shapes.isEmpty())
return;
2412 d->parent->canvas()->addCommand(cmd);
2418 Q_UNUSED(properties)
2419 Q_UNUSED(removeProperties)
2437 d->compressor.start();
2442 d->compressor.start();
2449 d->compressor.start();
2454 Q_FOREACH(
KoShape *shape,
d->shapes) {
2462 if (
d->parent->updateTextContourMode())
return;
2463 Q_FOREACH(
KoShape *shape,
d->shapes) {
2464 if (!shape)
continue;
2468 auto *textShapeGroup =
d->parent->tryFetchCurrentShapeManagerOwnerTextShape();
2470 if (textShapeGroup) {
2471 d->shapes = {textShapeGroup};
2473 d->shapes =
d->parent->canvas()->selectedShapesProxy()->selection()->selectedEditableShapes();
2476 Q_FOREACH(
KoShape *shape,
d->shapes) {
2477 if (!shape)
continue;
2480 d->compressor.start();
float value(const T *src, size_t ch)
void setText(const KUndo2MagicString &text)
KUndo2MagicString text() const
KisImageWSP image() const
KoShapeManager * localShapeManager() const
KisViewManager * viewManager() const
KisNodeSP activeNode()
Convenience function to get the active layer or mask.
The KisSignalMapper class bundles signals from identifiable senders.
void setMapping(QObject *sender, int id)
void setTextPropertiesInterface(KoSvgTextPropertiesInterface *interface)
setTextPropertiesInterface set the text properties interface. This should be done on tool activation....
KisNodeManager * nodeManager() const
The node manager handles everything about nodes.
KisTextPropertiesManager * textPropertyManager() const
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 KoShape * currentShapeManagerOwnerShape() const
the shape that owns the currently active shape manager
QPointer< KoShapeController > shapeController
virtual KoShapeManager * shapeManager() const =0
virtual const KoViewConverter * viewConverter() const =0
virtual void updateCanvas(const QRectF &rc)=0
virtual void addCommand(KUndo2Command *command)=0
QPointer< KoCanvasResourceProvider > resourceManager
virtual KoSelectedShapesProxy * selectedShapesProxy() const =0
selectedShapesProxy() is a special interface for keeping a persistent connections to selectionChanged...
bool setSvg(const QList< KoShape * > shapes)
KoToolBase * tool() const
The position of a path point within a path shape.
bool separate(QList< KoPathShape * > &separatedPaths)
Creates separate path shapes, one for each existing subpath.
int subpathCount() const
Returns the number of subpaths in the path.
static KoPathShape * createShapeFromPainterPath(const QPainterPath &path)
Creates path shape from given QPainterPath.
Qt::MouseButtons buttons() const
return buttons pressed (see QMouseEvent::buttons());
bool isTabletEvent() const
Qt::KeyboardModifiers modifiers() const
QPointF point
The point in document coordinates.
virtual KoSelection * selection()=0
void deselectAll()
clear the selections list
const QList< KoShape * > selectedEditableShapesAndDelegates() const
void select(KoShape *shape)
const QList< KoShape * > selectedEditableShapes() const
KoShape * firstSelectedShape() const
const QList< KoShape * > selectedShapes() const
The undo / redo command for aligning shapes.
Align
The different alignment options for this command.
@ VerticalTopAlignment
Align top.
@ VerticalCenterAlignment
Align centered vertically.
@ HorizontalLeftAlignment
Align left.
@ HorizontalCenterAlignment
Align Centered horizontally.
@ VerticalBottomAlignment
Align bottom.
@ HorizontalRightAlignment
Align Right.
QList< KoShape * > shapes() const
The undo / redo command for distributing shapes.
Distribute
The different options to distribute with this command.
@ HorizontalRightDistribution
Horizontal Right.
@ VerticalTopDistribution
Vertical top.
@ VerticalCenterDistribution
Vertical centered.
@ HorizontalGapsDistribution
Horizontal Gaps.
@ VerticalBottomDistribution
Vertical bottom.
@ HorizontalCenterDistribution
Horizontal centered.
@ HorizontalLeftDistribution
Horizontal Left.
@ VerticalGapsDistribution
Vertical Gaps.
QVector< Handle > handles() const
The undo / redo command for grouping shapes.
QList< KoShape * > topLevelShapes() const
KoShape * shapeAt(const QPointF &position, KoFlake::ShapeSelection selection=KoFlake::ShapeOnTop, bool omitHiddenShapes=true)
The KoShapeMergeTextPropertiesCommand class This sets text properties on given text shapes....
QVector< Handle > handles() const
get all nodes in the mesh, don't use this for drawing the path but use path()
The undo / redo command for shape moving.
MoveShapeType
An enum for defining what kind of reordering to use.
@ RaiseShape
raise the selected shape to the level that it is above the shape that is on top of it.
@ SendToBack
Lower the selected shape to be below all other shapes.
@ LowerShape
Lower the selected shape to the level that it is below the shape that is below it.
@ BringToFront
Raise the selected shape to be on top of all shapes.
static KoShapeReorderCommand * createCommand(const QList< KoShape * > &shapes, KoShapeManager *manager, MoveShapeType move, KUndo2Command *parent=0)
virtual SelectionMode currentMode() const
QRectF selectedRectangle() const
void paint(QPainter &painter, const KoViewConverter &converter, const KoColorDisplayRendererInterface *displayRendererInterface) override
The undo / redo command for ungrouping shapes.
virtual QRectF outlineRect() const
void addShapeChangeListener(ShapeChangeListener *listener)
void setZIndex(qint16 zIndex)
virtual QPainterPath outline() const
bool isSelectable() const
QPointF absolutePosition(KoFlake::AnchorPosition anchor=KoFlake::Center) const
void removeShapeChangeListener(ShapeChangeListener *listener)
virtual KoShapeStrokeModelSP stroke() const
static bool compareShapeZIndex(KoShape *s1, KoShape *s2)
bool isGeometryProtected() const
QRectF absoluteOutlineRect() const
KoShapeContainer * parent() const
virtual void setStroke(KoShapeStrokeModelSP stroke)
QTransform absoluteTransformation() const
virtual void setBackground(QSharedPointer< KoShapeBackground > background)
ChangeType
Used by shapeChanged() to select which change was made.
virtual QSharedPointer< KoShapeBackground > background() const
QTransform transformation() const
Returns the shapes local transformation matrix.
void paint(QPainter &painter, const KoViewConverter &converter, const KoColorDisplayRendererInterface *displayRenderer)
paints the guide
QRectF boundingRect()
returns the bounding rect of the guide
bool isSnapping() const
returns if snapping is enabled
The SvgConvertTextTypeCommand class This command allows textshapes to be converted between preformatt...
The KoSvgTextPropertiesInterface class.
void textSelectionChanged()
Emit to signal to KisTextPropertiesManager to call getSelectedProperties.
@ TextAnchorId
KoSvgText::TextAnchor.
QVariant propertyOrDefault(PropertyId id) const
static void removeContourShapesFromFlow(KoSvgTextShape *textShape, KUndo2Command *parent, bool textInShape, bool textPaths)
removeContourShapesFromFlow Create a command to remove all contour shapes of a certain type from the ...
The KoSvgTextReorderShapeInsideCommand class Within a text shape, the order of the shapes inside dete...
The KoSvgTextShapeOutlineHelper class helper class that draws the text outlines and contour mode butt...
KoSvgText::Direction direction() const
direction Whether the text is left to right or right to left.
@ PreformattedText
Text-on-Path falls under this or PrePositionedText depending on collapse of lines.
@ TextInShape
Uses shape-inside to wrap and preserves spaces.
@ InlineWrap
Uses inline size to wrap and preserves spaces.
QList< KoShape * > shapesInside
bool shapeInContours(KoShape *shape)
shapeInContours
TextType textType() const
textType This enum gives an indication of what kind of text this shape is. The different text types a...
int posForIndex(int index, bool firstIndex=false, bool skipSynthetic=false) const
posForIndex Get the cursor position for a given index in a string.
QList< KoShape * > shapesSubtract
KoSvgTextProperties textProperties() const
virtual QPointF viewToDocument(const QPointF &viewPoint) const
virtual QPointF documentToView(const QPointF &documentPoint) const
KUndo2Command * createCommand() override
void finishInteraction(Qt::KeyboardModifiers) override
void paint(QPainter &painter, const KoViewConverter &converter, const KoColorDisplayRendererInterface *displayRendererInterface) override
NopInteractionStrategy(KoToolBase *parent)
void handleMouseMove(const QPointF &, Qt::KeyboardModifiers) override
QPointer< KoSelection > m_selection
SelectionHandler(DefaultTool *parent)
bool hasSelection() override
return true if the tool currently has something selected that can be copied or deleted.
void cancelInteraction() override
void finishInteraction(Qt::KeyboardModifiers modifiers=QFlags< Qt::KeyboardModifier >()) override
SelectionInteractionStrategy(KoToolBase *parent, const QPointF &clicked, bool useSnapToGrid)
void paint(QPainter &painter, const KoViewConverter &converter, const KoColorDisplayRendererInterface *displayRendererInterface) override
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
#define KIS_ASSERT_RECOVER_RETURN(cond)
qreal kisSquareDistance(const QPointF &pt1, const QPointF &pt2)
bool isSelectionMask(KisNodeSP node)
KUndo2MagicString kundo2_i18n(const char *text)
KUndo2MagicString kundo2_noi18n(const QString &text)
@ PageSize
The size of the (current) page in postscript points.
@ ShapeOnTop
return the shape highest z-ordering, regardless of selection.
@ NextUnselected
return the first unselected directly under a selected shape, or the top most one if nothing is select...
SelectionHandle
Enum determining which handle is meant, used in KoInteractionTool.
@ BottomRightHandle
The handle that is at the bottom right of a selection.
@ BottomLeftHandle
The handle that is at the bottom left of a selection.
@ RightMiddleHandle
The handle that is at the right - center of a selection.
@ TopRightHandle
The handle that is at the top - right of a selection.
@ TopLeftHandle
The handle that is at the top left of a selection.
@ LeftMiddleHandle
The handle that is at the left center of a selection.
@ NoHandle
Value to indicate no handle.
@ TopMiddleHandle
The handle that is at the top - center of a selection.
@ BottomMiddleHandle
The handle that is at the bottom center of a selection.
TextAnchor
Where the text is anchored for SVG 1.1 text and 'inline-size'.
@ AnchorEnd
Anchor right for LTR, left for RTL.
@ AnchorStart
Anchor left for LTR, right for RTL.
@ AnchorMiddle
Anchor to the middle.
QTransform pathShapeBooleanSpaceWorkaround(KisImageSP image)
Interface to interact with the text property manager.
virtual bool spanSelection() override
Whether the tool is currently selecting a set of characters instead of whole paragraphs.
void slotSelectionChanged()
virtual bool characterPropertiesEnabled() override
Whether character selections are possible at all.
~DefaultToolTextPropertiesInterface()
virtual QList< KoSvgTextProperties > getSelectedProperties() override
getSelectedProperties
const QScopedPointer< Private > d
virtual void notifyShapeChanged(KoShape::ChangeType type, KoShape *shape) override
DefaultToolTextPropertiesInterface(DefaultTool *parent)
virtual KoSvgTextProperties getInheritedProperties() override
getInheritedProperties The properties that should be visible when a given property isn't available in...
QList< KoShape * > shapes
virtual void notifyCursorPosChanged(int pos, int anchor) override
Private(DefaultTool *parent)
KisSignalCompressor compressor
virtual void notifyMarkupChanged() override
virtual void setCharacterPropertiesOnSelected(KoSvgTextProperties properties, QSet< KoSvgTextProperties::PropertyId > removeProperties=QSet< KoSvgTextProperties::PropertyId >()) override
setCharacterPropertiesOnSelected This sets the properties for a character selection instead of the fu...
virtual QList< KoSvgTextProperties > getCharacterProperties() override
getSelectedProperties
virtual void setPropertiesOnSelected(KoSvgTextProperties properties, QSet< KoSvgTextProperties::PropertyId > removeProperties=QSet< KoSvgTextProperties::PropertyId >()) override
setPropertiesOnSelected This sets the properties on the selection. The implementation is responsible ...
bool startOffsetIsPercentage