66#include <QPainterPath>
71#include <QActionGroup>
87#define HANDLE_DISTANCE 10
88#define HANDLE_DISTANCE_SQ (HANDLE_DISTANCE * HANDLE_DISTANCE)
90#define INNER_HANDLE_DISTANCE_SQ 16
93static const QString EditFillGradientFactoryId =
"edit_fill_gradient";
94static const QString EditStrokeGradientFactoryId =
"edit_stroke_gradient";
95static const QString EditFillMeshGradientFactoryId =
"edit_fill_meshgradient";
97enum TransformActionType {
153 void finishInteraction(Qt::KeyboardModifiers modifiers = QFlags<Qt::KeyboardModifier>())
override
167 Q_FOREACH (
KoShape * shape, shapes) {
234 if (shapes.size() == 1) {
235 shape = shapes.first();
247 const qreal distanceThresholdSq =
253 qreal minDistanceSq = std::numeric_limits<qreal>::max();
261 if (distanceSq < distanceThresholdSq && distanceSq < minDistanceSq) {
263 minDistanceSq = distanceSq;
355 if (shapes.size() == 1) {
356 shape = shapes.first();
370 const qreal distanceThresholdSq =
376 qreal minDistanceSq = std::numeric_limits<qreal>::max();
380 for (
const auto& handle: sh.
handles()) {
381 const QPointF handlePoint = converter->
documentToView(handle.pos);
384 if (distanceSq < distanceThresholdSq && distanceSq < minDistanceSq) {
386 minDistanceSq = distanceSq;
424 , m_hotPosition(
KoFlake::TopLeft)
425 , m_mouseWasInsideHandles(false)
428 , m_tabbedOptionWidget(0)
433 QPixmap rotatePixmap, shearPixmap;
434 rotatePixmap.load(
":/cursor_rotate.png");
435 Q_ASSERT(!rotatePixmap.isNull());
436 shearPixmap.load(
":/cursor_shear.png");
437 Q_ASSERT(!shearPixmap.isNull());
439 m_rotateCursors[0] = QCursor(rotatePixmap.transformed(QTransform().rotate(45)));
440 m_rotateCursors[1] = QCursor(rotatePixmap.transformed(QTransform().rotate(90)));
441 m_rotateCursors[2] = QCursor(rotatePixmap.transformed(QTransform().rotate(135)));
442 m_rotateCursors[3] = QCursor(rotatePixmap.transformed(QTransform().rotate(180)));
443 m_rotateCursors[4] = QCursor(rotatePixmap.transformed(QTransform().rotate(225)));
444 m_rotateCursors[5] = QCursor(rotatePixmap.transformed(QTransform().rotate(270)));
445 m_rotateCursors[6] = QCursor(rotatePixmap.transformed(QTransform().rotate(315)));
458 m_shearCursors[1] = QCursor(shearPixmap.transformed(QTransform().rotate(45)));
459 m_shearCursors[2] = QCursor(shearPixmap.transformed(QTransform().rotate(90)));
460 m_shearCursors[3] = QCursor(shearPixmap.transformed(QTransform().rotate(135)));
461 m_shearCursors[4] = QCursor(shearPixmap.transformed(QTransform().rotate(180)));
462 m_shearCursors[5] = QCursor(shearPixmap.transformed(QTransform().rotate(225)));
463 m_shearCursors[6] = QCursor(shearPixmap.transformed(QTransform().rotate(270)));
464 m_shearCursors[7] = QCursor(shearPixmap.transformed(QTransform().rotate(315)));
474 if (connectToSelectedShapesProxy) {
495 1, EditFillGradientFactoryId,
this));
507 0, EditStrokeGradientFactoryId,
this));
521 EditFillMeshGradientFactoryId,
this));
538 if (shapes.isEmpty())
return;
542 bool convertableShape =
false;
544 Q_FOREACH(
KoShape *shape, shapes) {
546 if (textShape && textShape->
textType() != type) {
548 if (!convertableShape) {
549 convertableShape =
true;
557 if (convertableShape) {
571 if (selectedShapes.isEmpty())
return;
573 Q_FOREACH(
KoShape *shape, selectedShapes) {
575 if (text && !textShape) {
578 shapes.append(shape);
581 if (!textShape)
return;
582 if (shapes.isEmpty())
return;
592 Q_FOREACH(
KoShape *shape, shapes) {
611 if (selectedShapes.isEmpty())
return;
613 Q_FOREACH(
KoShape *shape, selectedShapes) {
615 if (text && !textShape) {
620 if (textShape && textPath) {
624 if (!(textShape && textPath))
return;
656 if (selectedShapes.isEmpty())
return;
658 Q_FOREACH(
KoShape *shape, selectedShapes) {
660 if (text && !textShape) {
663 shapes.append(shape);
666 if (!textShape)
return;
667 if (shapes.isEmpty())
return;
677 Q_FOREACH(
KoShape *shape, shapes) {
695 if (!textShape)
return;
700 if (selectedShapes.isEmpty())
return;
705 Q_FOREACH(
KoShape *shape, selectedShapes) {
717 if (!textShape)
return;
722 if (selectedShapes.isEmpty())
return;
725 bool addToCanvas =
false;
726 Q_FOREACH(
KoShape *shape, selectedShapes) {
740 if (!textShape)
return;
745 if (selectedShapes.isEmpty())
return;
759 Q_FOREACH(
KoShape *shape, selectedShapes) {
760 if (!textShape->
shapesInside().contains(shape))
continue;
761 shapesInside.append(shape);
764 if (!shapesInside.isEmpty()) {
782 QAction *a =
action(actionId);
783 connect(a, SIGNAL(triggered()), mapper, SLOT(map()));
830 if (!
action(
"text_type_preformatted")->actionGroup()) {
831 QActionGroup *textTypeActions =
new QActionGroup(
this);
832 textTypeActions->addAction(
action(
"text_type_preformatted"));
833 textTypeActions->addAction(
action(
"text_type_inline_wrap"));
834 textTypeActions->addAction(
action(
"text_type_pre_positioned"));
835 textTypeActions->setExclusive(
true);
855 if (useEdgeRotation) {
861 direction = handlePosition - selectionCenter;
868 if (useEdgeRotation) {
874 direction = handlePosition - selectionCenter;
881 if (useEdgeRotation) {
887 direction = handlePosition - selectionCenter;
895 if (useEdgeRotation) {
901 direction = handlePosition - selectionCenter;
913 qreal rotation = atan2(direction.y(), direction.x()) * 180.0 /
M_PI;
917 if (useEdgeRotation) {
927 if (useEdgeRotation) {
937 if (useEdgeRotation) {
947 if (useEdgeRotation) {
960 if (rotation < 0.0) {
971 QCursor
cursor = Qt::ArrowCursor;
977 bool editable = !
selection->selectedEditableShapes().isEmpty();
981 int rotOctant = 8 + int(8.5 +
m_angle / 45);
983 bool rotateHandle =
false;
984 bool shearHandle =
false;
1000 rotateHandle =
true;
1008 rotateHandle =
true;
1016 rotateHandle =
true;
1019 cursor = Qt::ArrowCursor;
1023 statusText = i18n(
"Left click rotates around center, right click around highlighted position.");
1026 statusText = i18n(
"Click and drag to shear selection.");
1031 statusText = i18n(
"Click and drag to resize selection.");
1033 int rotOctant = 8 + int(8.5 +
m_angle / 45);
1034 bool cornerHandle =
false;
1041 cornerHandle =
true;
1048 cornerHandle =
true;
1055 cornerHandle =
true;
1062 cornerHandle =
true;
1065 cursor = Qt::SizeAllCursor;
1066 statusText = i18n(
"Click and drag to move selection.");
1070 statusText = i18n(
"Click and drag to resize selection. Middle click to set highlighted position.");
1074 cursor = Qt::ArrowCursor;
1099 const bool isSelectionMask = node && node->inherits(
"KisSelectionMask");
1146 i18n(
"This tool only works on vector layers. You probably want the move tool."),
1168 if (bound.contains(event->
point)) {
1205 bound.adjust(-border.x(), -border.y(), border.x(), border.y());
1222 if (!(event->
modifiers() & Qt::ShiftModifier)) {
1234 bool result =
false;
1236 qreal x = 0.0, y = 0.0;
1237 if (direction == Qt::Key_Left) {
1239 }
else if (direction == Qt::Key_Right) {
1241 }
else if (direction == Qt::Key_Up) {
1243 }
else if (direction == Qt::Key_Down) {
1247 if (x != 0.0 || y != 0.0) {
1249 if ((modifiers & Qt::ShiftModifier) != 0) {
1252 }
else if ((modifiers & Qt::AltModifier) != 0) {
1259 if (!shapes.isEmpty()) {
1272 switch (event->key()) {
1311 if (!shapes.isEmpty()) {
1327 if (!shapes.empty()) {
1341 Q_ASSERT(
canvas()->selectedShapesProxy());
1354 Q_ASSERT(
canvas()->selectedShapesProxy());
1362 Q_ASSERT(
canvas()->selectedShapesProxy());
1390 if (innerHandleMeaning) {
1393 *innerHandleMeaning = path.contains(point) || path.intersects(
handlePaintRect(point));
1407 if (innerHandleMeaning) {
1409 *innerHandleMeaning =
true;
1423 QTransform matrix =
selection->absoluteTransformation();
1440 if (s->scaleX() < 0) {
1445 if (s->scaleY() < 0) {
1458 QAction *actionBringToFront =
action(
"object_order_front");
1459 connect(actionBringToFront, SIGNAL(triggered()),
this, SLOT(
selectionBringToFront()), Qt::UniqueConnection);
1461 QAction *actionRaise =
action(
"object_order_raise");
1462 connect(actionRaise, SIGNAL(triggered()),
this, SLOT(
selectionMoveUp()), Qt::UniqueConnection);
1464 QAction *actionLower =
action(
"object_order_lower");
1467 QAction *actionSendToBack =
action(
"object_order_back");
1468 connect(actionSendToBack, SIGNAL(triggered()),
this, SLOT(
selectionSendToBack()), Qt::UniqueConnection);
1470 QAction *actionGroupBottom =
action(
"object_group");
1471 connect(actionGroupBottom, SIGNAL(triggered()),
this, SLOT(
selectionGroup()), Qt::UniqueConnection);
1473 QAction *actionUngroupBottom =
action(
"object_ungroup");
1474 connect(actionUngroupBottom, SIGNAL(triggered()),
this, SLOT(
selectionUngroup()), Qt::UniqueConnection);
1476 QAction *actionSplit =
action(
"object_split");
1477 connect(actionSplit, SIGNAL(triggered()),
this, SLOT(
selectionSplitShapes()), Qt::UniqueConnection);
1486 QAction *actionTextInside =
action(
"add_shape_to_flow_area");
1487 connect(actionTextInside, SIGNAL(triggered()),
this, SLOT(
slotAddShapesToFlow()), Qt::UniqueConnection);
1489 QAction *actionTextSubtract =
action(
"subtract_shape_from_flow_area");
1492 QAction *actionTextOnPath =
action(
"put_text_on_path");
1493 connect(actionTextOnPath, SIGNAL(triggered()),
this, SLOT(
slotPutTextOnPath()), Qt::UniqueConnection);
1495 QAction *actionTextRemoveFlow =
action(
"remove_shapes_from_text_flow");
1498 QAction *actionTextFlowToggle =
action(
"flow_shape_type_toggle");
1499 connect(actionTextFlowToggle, SIGNAL(triggered()),
this, SLOT(
slotToggleFlowShapeType()), Qt::UniqueConnection);
1507 const KisCanvas2 *canvas2 = qobject_cast<const KisCanvas2 *>(this->
canvas());
1522 QAction *actionBringToFront =
action(
"object_order_front");
1523 disconnect(actionBringToFront, 0,
this, 0);
1525 QAction *actionRaise =
action(
"object_order_raise");
1526 disconnect(actionRaise, 0,
this, 0);
1528 QAction *actionLower =
action(
"object_order_lower");
1529 disconnect(actionLower, 0,
this, 0);
1531 QAction *actionSendToBack =
action(
"object_order_back");
1532 disconnect(actionSendToBack, 0,
this, 0);
1534 QAction *actionGroupBottom =
action(
"object_group");
1535 disconnect(actionGroupBottom, 0,
this, 0);
1537 QAction *actionUngroupBottom =
action(
"object_ungroup");
1538 disconnect(actionUngroupBottom, 0,
this, 0);
1540 QAction *actionSplit =
action(
"object_split");
1541 disconnect(actionSplit, 0,
this, 0);
1550 QAction *actionTextInside =
action(
"add_shape_to_flow_area");
1551 disconnect(actionTextInside, 0,
this, 0);
1552 QAction *actionTextSubtract =
action(
"subtract_shape_from_flow_area");
1553 disconnect(actionTextSubtract, 0,
this, 0);
1554 QAction *actionTextOnPath =
action(
"put_text_on_path");
1555 disconnect(actionTextOnPath, 0,
this, 0);
1556 QAction *actionTextRemoveFlow =
action(
"remove_shapes_from_text_flow");
1557 disconnect(actionTextRemoveFlow, 0,
this, 0);
1558 QAction *actionTextFlowToggle =
action(
"flow_shape_type_toggle");
1559 disconnect(actionTextFlowToggle, 0,
this, 0);
1561 const KisCanvas2 *canvas2 = qobject_cast<const KisCanvas2 *>(this->
canvas());
1579 if (selectedShapes.isEmpty())
return;
1581 const int groupZIndex = selectedShapes.last()->zIndex();
1610 Q_FOREACH (
KoShape *shape, selectedShapes) {
1617 newShapes << group->
shapes();
1636 if (editableShapes.isEmpty()) {
1640 QTransform applyTransform;
1641 bool shouldReset =
false;
1645 switch (TransformActionType(transformAction)) {
1646 case TransformRotate90CW:
1647 applyTransform.rotate(90.0);
1648 actionName =
kundo2_i18n(
"Rotate Object 90° CW");
1650 case TransformRotate90CCW:
1651 applyTransform.rotate(-90.0);
1652 actionName =
kundo2_i18n(
"Rotate Object 90° CCW");
1654 case TransformRotate180:
1655 applyTransform.rotate(180.0);
1658 case TransformMirrorX:
1659 applyTransform.scale(-1.0, 1.0);
1660 actionName =
kundo2_i18n(
"Mirror Object Horizontally");
1662 case TransformMirrorY:
1663 applyTransform.scale(1.0, -1.0);
1664 actionName =
kundo2_i18n(
"Mirror Object Vertically");
1666 case TransformReset:
1668 actionName =
kundo2_i18n(
"Reset Object Transformations");
1672 if (!shouldReset && applyTransform.isIdentity())
return;
1678 const QPointF centerPoint = outlineRect.center();
1679 const QTransform centerTrans = QTransform::fromTranslate(centerPoint.x(), centerPoint.y());
1680 const QTransform centerTransInv = QTransform::fromTranslate(-centerPoint.x(), -centerPoint.y());
1686 Q_FOREACH (
KoShape *shape, transformedShapes) {
1693 t = world * centerTransInv * applyTransform * centerTrans * world.inverted() * shape->
transformation();
1695 const QPointF center = shape->
outlineRect().center();
1696 const QPointF offset = shape->
transformation().map(center) - center;
1697 t = QTransform::fromTranslate(offset.x(), offset.y());
1700 newTransforms.append(t);
1714 if (editableShapes.isEmpty()) {
1719 QPainterPath dstOutline;
1723 const int referenceShapeIndex = 0;
1724 KoShape *referenceShape = editableShapes[referenceShapeIndex];
1728 const QTransform booleanWorkaroundTransform =
1731 Q_FOREACH (
KoShape *shape, editableShapes) {
1733 booleanWorkaroundTransform.map(
1738 if (booleanOp == BooleanUnion) {
1739 Q_FOREACH (
const QPainterPath &path, srcOutlines) {
1743 }
else if (booleanOp == BooleanIntersection) {
1744 for (
int i = 0; i < srcOutlines.size(); i++) {
1746 dstOutline = srcOutlines[i];
1748 dstOutline &= srcOutlines[i];
1754 dstOutline.closeSubpath();
1758 }
else if (booleanOp == BooleanSubtraction) {
1759 for (
int i = 0; i < srcOutlines.size(); i++) {
1760 dstOutline = srcOutlines[referenceShapeIndex];
1761 if (i != referenceShapeIndex) {
1762 dstOutline -= srcOutlines[i];
1769 dstOutline = booleanWorkaroundTransform.inverted().map(dstOutline);
1773 if (!dstOutline.isEmpty()) {
1791 newSelectedShapes << newShape;
1807 if (editableShapes.isEmpty()) {
1816 Q_FOREACH (
KoShape *shape, editableShapes) {
1818 if (!pathShape)
return;
1821 if (pathShape->
separate(splitShapes)) {
1822 QList<KoShape*> normalShapes = implicitCastList<KoShape*>(splitShapes);
1827 newShapes << normalShapes;
1845 if (editableShapes.isEmpty()) {
1855 if (editableShapes.count() == 1) {
1877 if (editableShapes.size() < 3) {
1914 if (selectedShapes.isEmpty()) {
1936 SIGNAL(sigSwitchModeEditFillGradient(
bool)),
1940 SIGNAL(sigSwitchModeEditStrokeGradient(
bool)),
1944 SIGNAL(sigSwitchModeEditFillGradient(
bool)),
1949 SIGNAL(sigMeshGradientResetted()),
1968 bool insideSelection =
false;
1971 bool editableShape = !
selection->selectedEditableShapes().isEmpty();
1973 const bool selectMultiple =
event->modifiers() & Qt::ShiftModifier;
1974 const bool selectNextInStack =
event->modifiers() & Qt::ControlModifier;
1975 const bool avoidSelection =
event->modifiers() & Qt::AltModifier;
1977 if (selectNextInStack) {
2027 if (!avoidSelection && editableShape) {
2031 if (insideSelection) {
2050 if (!selectMultiple && !selectNextInStack) {
2052 if (insideSelection) {
2061 if (!selectMultiple) {
2068 if (selectMultiple) {
2072 if (!selectMultiple) {
2093 const bool hasEditableShapes = !editableShapes.isEmpty();
2095 action(
"object_order_front")->setEnabled(hasEditableShapes);
2096 action(
"object_order_raise")->setEnabled(hasEditableShapes);
2097 action(
"object_order_lower")->setEnabled(hasEditableShapes);
2098 action(
"object_order_back")->setEnabled(hasEditableShapes);
2100 action(
"object_transform_rotate_90_cw")->setEnabled(hasEditableShapes);
2101 action(
"object_transform_rotate_90_ccw")->setEnabled(hasEditableShapes);
2102 action(
"object_transform_rotate_180")->setEnabled(hasEditableShapes);
2103 action(
"object_transform_mirror_horizontally")->setEnabled(hasEditableShapes);
2104 action(
"object_transform_mirror_vertically")->setEnabled(hasEditableShapes);
2105 action(
"object_transform_reset")->setEnabled(hasEditableShapes);
2107 const bool multipleSelected = editableShapes.size() > 1;
2109 const bool alignmentEnabled =
2111 (!editableShapes.isEmpty() &&
2114 action(
"object_align_horizontal_left")->setEnabled(alignmentEnabled);
2115 action(
"object_align_horizontal_center")->setEnabled(alignmentEnabled);
2116 action(
"object_align_horizontal_right")->setEnabled(alignmentEnabled);
2117 action(
"object_align_vertical_top")->setEnabled(alignmentEnabled);
2118 action(
"object_align_vertical_center")->setEnabled(alignmentEnabled);
2119 action(
"object_align_vertical_bottom")->setEnabled(alignmentEnabled);
2121 const bool distributionEnabled = editableShapes.size() > 2;
2123 action(
"object_distribute_horizontal_left")->setEnabled(distributionEnabled);
2124 action(
"object_distribute_horizontal_center")->setEnabled(distributionEnabled);
2125 action(
"object_distribute_horizontal_right")->setEnabled(distributionEnabled);
2126 action(
"object_distribute_horizontal_gaps")->setEnabled(distributionEnabled);
2128 action(
"object_distribute_vertical_top")->setEnabled(distributionEnabled);
2129 action(
"object_distribute_vertical_center")->setEnabled(distributionEnabled);
2130 action(
"object_distribute_vertical_bottom")->setEnabled(distributionEnabled);
2131 action(
"object_distribute_vertical_gaps")->setEnabled(distributionEnabled);
2134 bool textShape =
false;
2135 bool otherShapes =
false;
2136 bool shapesInside =
false;
2138 const bool editFlowShapes = bool(currentTextShapeGroup);
2139 Q_FOREACH(
KoShape *shape, editableShapes) {
2141 if (text && !textShape) {
2145 if (editFlowShapes) {
2146 if (!shapesInside && currentTextShapeGroup->
shapesInside().contains(shape)) {
2147 shapesInside =
true;
2151 if (textShape && otherShapes)
break;
2153 const bool editContours = textShape && otherShapes;
2155 action(
"add_shape_to_flow_area")->setEnabled(editContours);
2156 action(
"subtract_shape_from_flow_area")->setEnabled(editContours);
2157 action(
"put_text_on_path")->setEnabled(editContours);
2158 action(
"remove_shapes_from_text_flow")->setEnabled(editFlowShapes);
2159 action(
"flow_shape_type_toggle")->setEnabled(editFlowShapes);
2160 action(
"flow_shape_order_back")->setEnabled(shapesInside);
2161 action(
"flow_shape_order_earlier")->setEnabled(shapesInside);
2162 action(
"flow_shape_order_later")->setEnabled(shapesInside);
2163 action(
"flow_shape_order_front")->setEnabled(shapesInside);
2171 const bool multipleSelected = editableShapes.size() > 1;
2173 action(
"object_group")->setEnabled(multipleSelected);
2175 action(
"object_unite")->setEnabled(multipleSelected);
2176 action(
"object_intersect")->setEnabled(multipleSelected);
2177 action(
"object_subtract")->setEnabled(multipleSelected);
2179 bool hasShapesWithMultipleSegments =
false;
2180 Q_FOREACH (
KoShape *shape, editableShapes) {
2183 hasShapesWithMultipleSegments =
true;
2187 action(
"object_split")->setEnabled(hasShapesWithMultipleSegments);
2190 bool hasGroupShape =
false;
2191 foreach (
KoShape *shape, editableShapes) {
2193 hasGroupShape =
true;
2197 action(
"object_ungroup")->setEnabled(hasGroupShape);
2199 bool enablePreformatted =
false;
2200 bool enablePrePositioned =
false;
2201 bool enableInlineWrapped =
false;
2203 Q_FOREACH (
KoShape *shape, editableShapes) {
2208 enablePreformatted =
true;
2211 enablePrePositioned =
true;
2214 enableInlineWrapped =
true;
2218 QActionGroup *group =
action(
"text_type_preformatted")->actionGroup();
2219 group->setEnabled(
true);
2220 group->setExclusive(
false);
2221 Q_FOREACH (QAction *a, group->actions()) {
2222 a->setCheckable(
false);
2225 action(
"text_type_preformatted")->setEnabled(enablePreformatted);
2226 action(
"text_type_pre_positioned")->setEnabled(enablePrePositioned);
2227 action(
"text_type_inline_wrap")->setEnabled(enableInlineWrapped);
2244 QMenu *transform =
m_contextMenu->addMenu(i18n(
"Transform"));
2246 transform->addAction(
action(
"object_transform_rotate_90_cw"));
2247 transform->addAction(
action(
"object_transform_rotate_90_ccw"));
2248 transform->addAction(
action(
"object_transform_rotate_180"));
2249 transform->addSeparator();
2250 transform->addAction(
action(
"object_transform_mirror_horizontally"));
2251 transform->addAction(
action(
"object_transform_mirror_vertically"));
2252 transform->addSeparator();
2253 transform->addAction(
action(
"object_transform_reset"));
2255 if (
action(
"object_unite")->isEnabled() ||
2256 action(
"object_intersect")->isEnabled() ||
2257 action(
"object_subtract")->isEnabled() ||
2258 action(
"object_split")->isEnabled()) {
2260 QMenu *transform =
m_contextMenu->addMenu(i18n(
"Logical Operations"));
2261 transform->addAction(
action(
"object_unite"));
2262 transform->addAction(
action(
"object_intersect"));
2263 transform->addAction(
action(
"object_subtract"));
2264 transform->addAction(
action(
"object_split"));
2281 if (
action(
"object_group")->isEnabled() ||
action(
"object_ungroup")->isEnabled()) {
2291 text->addAction(
action(
"add_shape_to_flow_area"));
2292 text->addAction(
action(
"subtract_shape_from_flow_area"));
2293 text->addAction(
action(
"put_text_on_path"));
2294 text->addSeparator();
2295 text->addAction(
action(
"text_type_preformatted"));
2296 text->addAction(
action(
"text_type_inline_wrap"));
2297 text->addAction(
action(
"text_type_pre_positioned"));
2298 text->addSeparator();
2299 text->addAction(
action(
"remove_shapes_from_text_flow"));
2300 text->addAction(
action(
"flow_shape_type_toggle"));
2301 text->addSeparator();
2302 text->addAction(
action(
"flow_shape_order_back"));
2303 text->addAction(
action(
"flow_shape_order_earlier"));
2304 text->addAction(
action(
"flow_shape_order_later"));
2305 text->addAction(
action(
"flow_shape_order_front"));
2312 menu->addAction(
action(
"object_transform_rotate_90_cw"));
2313 menu->addAction(
action(
"object_transform_rotate_90_ccw"));
2314 menu->addAction(
action(
"object_transform_rotate_180"));
2315 menu->addSeparator();
2316 menu->addAction(
action(
"object_transform_mirror_horizontally"));
2317 menu->addAction(
action(
"object_transform_mirror_vertically"));
2318 menu->addSeparator();
2319 menu->addAction(
action(
"object_transform_reset"));
2326 QTimer::singleShot(0, [tool = std::move(tool)]() {
2357 if (!
d->parent->selection()->hasSelection())
return props;
2360 for (
auto it =
shapes.begin(); it !=
shapes.end(); it++) {
2362 if (!textShape)
continue;
2382 if (
d->shapes.isEmpty())
return;
2385 d->parent->canvas()->addCommand(cmd);
2391 Q_UNUSED(properties)
2392 Q_UNUSED(removeProperties)
2410 d->compressor.start();
2415 d->compressor.start();
2422 d->compressor.start();
2427 Q_FOREACH(
KoShape *shape,
d->shapes) {
2435 if (
d->parent->updateTextContourMode())
return;
2436 Q_FOREACH(
KoShape *shape,
d->shapes) {
2437 if (!shape)
continue;
2441 auto *textShapeGroup =
d->parent->tryFetchCurrentShapeManagerOwnerTextShape();
2443 if (textShapeGroup) {
2444 d->shapes = {textShapeGroup};
2446 d->shapes =
d->parent->canvas()->selectedShapesProxy()->selection()->selectedEditableShapes();
2449 Q_FOREACH(
KoShape *shape,
d->shapes) {
2450 if (!shape)
continue;
2453 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) 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)
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.
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...
@ 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 paint(QPainter &painter, const KoViewConverter &converter) override
void finishInteraction(Qt::KeyboardModifiers) 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
void paint(QPainter &painter, const KoViewConverter &converter) override
SelectionInteractionStrategy(KoToolBase *parent, const QPointF &clicked, bool useSnapToGrid)
#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.
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 ...