Krita Source Code Documentation
Loading...
Searching...
No Matches
KoSvgTextAddRemoveShapeCommands.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2025 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
7#include "kis_assert.h"
8#include <optional>
9#include "kis_debug.h"
10
12#include <KoSvgTextShape.h>
13#include <KoShapeContainer.h>
14
16 Private(KoSvgTextShape *_text, KoShape *_shape, int _startPos, int _endPos)
17 : textShape(_text)
18 , shape(_shape)
19 , startPos(_startPos)
20 , endPos(_endPos)
21 {
22
23 }
24
27 KoShape* shape = nullptr;
29 std::optional<KoShapeContainer*> originalShapeParent;
31 int startPos = -1;
32 int endPos = -1;
35};
36
38 : KisCommandUtils::FlipFlopCommand(state, parent)
39 , d(new Private(textShape, shape, startPos, endPos))
40{
41 d->removeCommand = state == FINALIZING;
42
43 if (type == Unknown) {
44 if (d->textShape->shapesInside().contains(shape)) {
45 d->type = Inside;
46 } else if (d->textShape->shapesSubtract().contains(shape)) {
47 d->type = Subtract;
48 } else if (d->textShape->shapeInContours(shape)){
49 d->type = TextPath;
50 KoSvgTextNodeIndex idx = textShape->nodeForTextPath(shape);
51 QPair<int, int> range = textShape->findRangeForNodeIndex(idx);
52 d->startPos = range.first;
53 d->endPos = range.second;
54 } else {
55 d->type = Unknown;
56 }
57 } else {
58 d->type = type;
59 }
60}
61
66
67// Remove shape from text.
69{
70 if (d->removeCommand) {
71 d->memento = d->textShape->getMemento();
72 d->oldTextPaths = d->textShape->textPathsAtRange(d->startPos, d->endPos);
73 }
74
75 KoShapeBulkActionLock lock(QList<KoShape*>({d->textShape, d->shape}));
76
77 KoShapeContainer *newParent = d->originalShapeParent.has_value() ? d->originalShapeParent.value() : d->textShape->parent();
78 const QTransform newParentTransform = newParent ? newParent->absoluteTransformation() : QTransform();
79 const QTransform absoluteTf = newParentTransform.inverted() * d->textShape->absoluteTransformation();
80
81 d->textShape->removeShapesFromContours({d->shape}, true);
82 // by this time d->shape->parent() is set to nullptr
83
84 if (newParent) {
85 // set new parent if exists
86 d->shape->setParent(newParent);
87 }
88
89 if (!d->removeCommand) {
90 Q_FOREACH(KoShape *path, d->oldTextPaths) {
91 if (!d->textShape->shapeInContours(path)) {
92 d->textShape->addTextPathAtEnd(path);
93 }
94 }
95 d->textShape->setMemento(d->memento);
96 } else {
97 d->textShape->relayout();
98 }
99 d->shape->applyAbsoluteTransformation(absoluteTf);
100
102}
103
104// Add shape to text.
106{
107 if (!d->removeCommand) {
108 d->memento = d->textShape->getMemento();
109 d->oldTextPaths = d->textShape->textPathsAtRange(d->startPos, d->endPos);
110 d->originalShapeParent = d->shape->parent();
111 }
112
113 KoShapeBulkActionLock lock(QList<KoShape*>({d->textShape, d->shape}));
114
115 KoShapeContainer *oldParent = d->shape->parent();
116 const QTransform oldParentTransform = oldParent ? oldParent->absoluteTransformation() : QTransform();
117 const QTransform absoluteTf = d->textShape->absoluteTransformation().inverted() * oldParentTransform;
118
119 if (d->type == Inside) {
120 d->textShape->addShapeContours({d->shape}, true);
121 } else if (d->type == Subtract) {
122 d->textShape->addShapeContours({d->shape}, false);
123 } else if (d->type == TextPath) {
124 d->textShape->setTextPathOnRange(d->shape, d->startPos, d->endPos);
125 }
126
127 if (d->removeCommand) {
128 Q_FOREACH(KoShape *path, d->oldTextPaths) {
129 if (!d->textShape->shapeInContours(path)) {
130 d->textShape->addTextPathAtEnd(path);
131 }
132 }
133 d->textShape->setMemento(d->memento);
134 } else {
135 d->textShape->relayout();
136 }
137 d->shape->applyAbsoluteTransformation(absoluteTf);
138
140}
141
143 : KoSvgTextAddRemoveShapeCommandImpl(textShape, shape, (inside? Inside: Subtract), INITIALIZING, -1, -1, parentCommand)
144{
151 KIS_SAFE_ASSERT_RECOVER_NOOP(!textShape->parent() || !shape->parent() || textShape->parent() == shape->parent());
152}
153
158
160: KoSvgTextAddRemoveShapeCommandImpl(textShape, shape, Unknown, FINALIZING, -1, -1, parentCommand)
161{
162 // the \p shape will be ungrouped into the parent of \p textShape
164}
165
170
171void KoSvgTextRemoveShapeCommand::removeContourShapesFromFlow(KoSvgTextShape *textShape, KUndo2Command *parent, bool textInShape, bool textPaths)
172{
173 QList<KoShape*> shapes;
174 if (textInShape) {
175 shapes.append(textShape->shapesInside());
176 shapes.append(textShape->shapesSubtract());
177 }
178 if (textPaths) {
179 shapes.append(textShape->textPathsAtRange(0, textShape->posForIndex(textShape->plainText().size())));
180 }
181 Q_FOREACH(KoShape *shape, shapes) {
182 new KoSvgTextRemoveShapeCommand(textShape, shape, parent);
183 }
184}
185
187: KoSvgTextAddRemoveShapeCommandImpl(textShape, shape, TextPath, INITIALIZING, startPos, endPos, parentCommand)
188{
189
190}
191
static void bulkShapesUpdate(const UpdatesList &updates)
KoShapeContainer * parent() const
Definition KoShape.cpp:862
QTransform absoluteTransformation() const
Definition KoShape.cpp:335
KoSvgTextAddRemoveShapeCommandImpl(KoSvgTextShape *textShape, KoShape *shape, ContourType type, State state, int startPos, int endPos, KUndo2Command *parent=nullptr)
KoSvgTextAddShapeCommand(KoSvgTextShape *textShape, KoShape *shape, bool inside, KUndo2Command *parentCommand=0)
The KoSvgTextNodeIndex class.
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 ...
KoSvgTextRemoveShapeCommand(KoSvgTextShape *textShape, KoShape *shape, KUndo2Command *parentCommand=0)
KoSvgTextSetTextPathOnRangeCommand(KoSvgTextShape *textShape, KoShape *shape, int startPos, int endPos, KUndo2Command *parentCommand=0)
QPair< int, int > findRangeForNodeIndex(const KoSvgTextNodeIndex &node) const
findRangeForNodeIndex Find the start and end cursor position for a given nodeIndex.
QList< KoShape * > shapesInside
bool shapeInContours(KoShape *shape)
shapeInContours
int posForIndex(int index, bool firstIndex=false, bool skipSynthetic=false) const
posForIndex Get the cursor position for a given index in a string.
KoSvgTextNodeIndex nodeForTextPath(KoShape *textPath) const
nodeForTextPath TextPaths are set on toplevel content elements. This function allows for searching wh...
QList< KoShape * > textPathsAtRange(const int startPos=-1, const int endPos=-1)
textPathsAtRange Get a list of textPaths at the given range. This includes textPaths whose node is on...
QList< KoShape * > shapesSubtract
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
@ Unknown
Definition psd.h:44
Private(KoSvgTextShape *_text, KoShape *_shape, int _startPos, int _endPos)
KoSvgTextAddRemoveShapeCommandImpl::ContourType type