Krita Source Code Documentation
Loading...
Searching...
No Matches
SvgTextChangeTransformsOnRange.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-3.0-or-later
5 */
7#include "kis_command_ids.h"
9
10SvgTextChangeTransformsOnRange::SvgTextChangeTransformsOnRange(KoSvgTextShape *shape, int startPos, int endPos, QVector<QPointF> positions, QVector<qreal> rotations, bool calculateDeltaPositions, KUndo2Command *parentCommand)
11 : KUndo2Command(parentCommand)
12 , m_textShape(shape)
13 , m_startPos(startPos)
14 , m_endPos(endPos)
15 , m_positions(positions)
16 , m_rotations(rotations)
17 , m_calculateDeltaPositions(calculateDeltaPositions)
18 , m_textData(shape->getMemento())
19{
20 setText(kundo2_i18n("Adjust character transforms on text."));
21}
22
23SvgTextChangeTransformsOnRange::SvgTextChangeTransformsOnRange(KoSvgTextShape *shape, int startPos, int endPos, QPointF delta, OffsetType type, bool calculateDeltaPositions, KUndo2Command *parentCommand)
24 : KUndo2Command(parentCommand)
25 , m_textShape(shape)
26 , m_startPos(startPos)
27 , m_endPos(endPos)
28 , m_calculateDeltaPositions(calculateDeltaPositions)
29 , m_textData(shape->getMemento())
30{
31 setText(kundo2_i18n("Adjust character transforms on text."));
32
33 QVector<QPointF> positions;
34 QVector<qreal> rotations;
35
36 QList<KoSvgTextCharacterInfo> originalTf = shape->getPositionsAndRotationsForRange(startPos, endPos);
37
38 if (type == OffsetAll) {
39
40 while (!originalTf.isEmpty()) {
41 KoSvgTextCharacterInfo tf = originalTf.takeFirst();
42 positions.append(tf.finalPos + delta);
43
44 rotations.append(tf.rotateDeg);
45 }
46 } else {
47 QTransform deltaTf = getTransformForOffset(shape, startPos, endPos, delta, type);
48 QLineF l(0, 0, 10, 0);
49 l.setAngle(0);
50 l = deltaTf.map(l);
51
52 while (!originalTf.isEmpty()) {
53 KoSvgTextCharacterInfo tf = originalTf.takeFirst();
54 if (type != RotateOnly) {
55 positions.append(deltaTf.map(tf.finalPos));
56 } else {
57 positions.append(tf.finalPos);
58 }
59 if (type != ScaleOnly) {
60 rotations.append(tf.rotateDeg - (l.angle()));
61 } else {
62 rotations.append(tf.rotateDeg);
63 }
64 }
65 }
66
67 m_positions = positions;
68 m_rotations = rotations;
69
70}
71
83
97
102
104 const SvgTextChangeTransformsOnRange *other = dynamic_cast<const SvgTextChangeTransformsOnRange *>(otherCommand);
105
106 if (!other || other->m_textShape != m_textShape || other->m_startPos != m_startPos || other->m_endPos != m_endPos || other->m_calculateDeltaPositions != m_calculateDeltaPositions) {
107 return false;
108 }
109
110 m_positions = other->m_positions;
111 m_rotations = other->m_rotations;
112 return true;
113}
114
115QTransform SvgTextChangeTransformsOnRange::getTransformForOffset(KoSvgTextShape *shape, int startPos, int endPos, QPointF delta, OffsetType type)
116{
117 QTransform deltaTf;
118 if (type == OffsetAll) {
119 return QTransform::fromTranslate(delta.x(), delta.y());
120 } else {
121 const int lineEnd = qMin(shape->lineEnd(qMin(startPos, endPos)), qMax(startPos, endPos));
123 shape->getPositionsAndRotationsForRange(qMin(startPos, endPos), lineEnd);
124 if (infos.size() < 1) return deltaTf;
125 const bool rtl = infos.first().rtl;
126 KoSvgTextCharacterInfo first = infos.first();
127 KoSvgTextCharacterInfo last = infos.last();
128 if (infos.size() > 1) {
129 std::sort(infos.begin(), infos.end(), KoSvgTextCharacterInfo::visualLessThan);
130 for (auto it = infos.begin(); it != infos.end(); it++) {
131 if (it->visualIndex >= 0) {
132 first = *it;
133 break;
134 }
135 }
136 for (auto it = infos.rbegin(); it != infos.rend(); it++) {
137 if (it->visualIndex >= 0) {
138 last = *it;
139 break;
140 }
141 }
142 }
143 QTransform t = QTransform::fromTranslate(last.finalPos.x(), last.finalPos.y());
144 t.rotate(last.rotateDeg);
145 last.finalPos = t.map(last.advance);
146
147 QLineF originalLine(rtl? last.finalPos: first.finalPos, rtl? first.finalPos: last.finalPos);
148 QLineF newLine(originalLine.p1(), originalLine.p2() + delta);
149
150 const qreal scale = newLine.length()/originalLine.length();
151
152 QTransform origin = QTransform::fromTranslate(originalLine.p1().x(), originalLine.p1().y());
153 qreal angle = originalLine.angle() - newLine.angle();
154
155 deltaTf = origin.inverted();
156 deltaTf *= QTransform::fromScale(scale, scale);
157 deltaTf *= QTransform().rotate(angle);
158 deltaTf *= origin;
159 }
160 return deltaTf;
161}
void setText(const KUndo2MagicString &text)
static void bulkShapesUpdate(const UpdatesList &updates)
void notifyCursorPosChanged(int pos, int anchor)
Notify that the cursor position has changed.
bool setCharacterTransformsOnRange(const int startPos, const int endPos, const QVector< QPointF > positions, const QVector< qreal > rotateDegrees, const bool deltaPosition=true)
setCharacterTransformsOnRange Set SVG 1.1 style character transforms on the given range....
void setMemento(const KoSvgTextShapeMementoSP memento)
Set the text data and layout info, reset listening cursors to 0.
int indexForPos(int pos) const
indexForPos get the string index for a given cursor position.
int lineEnd(int pos)
lineEnd return the 'line end' for this pos. This uses anchored chunks, so each absolute x,...
int posForIndex(int index, bool firstIndex=false, bool skipSynthetic=false) const
posForIndex Get the cursor position for a given index in a string.
QList< KoSvgTextCharacterInfo > getPositionsAndRotationsForRange(const int startPos, const int endPos) const
getPositionsAndRotationsForRange
bool mergeWith(const KUndo2Command *other) override
SvgTextChangeTransformsOnRange(KoSvgTextShape *shape, int startPos, int endPos, QVector< QPointF > positions, QVector< qreal > rotations, bool calculateDeltaPositions, KUndo2Command *parentCommand=nullptr)
static QTransform getTransformForOffset(KoSvgTextShape *shape, int startPos, int endPos, QPointF delta, OffsetType type)
getTransformForOffset Function to get the expected transform, so we can test this command better.
KUndo2MagicString kundo2_i18n(const char *text)
@ SvgTextChangeTransformsOnRangeCommandId
The KoSvgTextCharacterInfo class This is a small struct to convey information about character positio...
static bool visualLessThan(const KoSvgTextCharacterInfo &a, const KoSvgTextCharacterInfo &b)