Krita Source Code Documentation
Loading...
Searching...
No Matches
SvgInlineSizeChangeStrategy.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2023 Alvin Wong <alvin@alvinhc.com>
3 *
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
10#include "SvgInlineSizeHelper.h"
11
12#include "KoSvgText.h"
13#include "KoSvgTextProperties.h"
14#include "KoSvgTextShape.h"
15#include "KoSnapGuide.h"
16
17#include "KoCanvasBase.h"
18#include "KoToolBase.h"
19#include "kis_assert.h"
20#include "kis_global.h"
21
25
27 KoSvgTextShape *shape,
28 const QPointF &clicked, bool start)
30 , m_shape(shape)
31 , m_dragStart(clicked)
32 , m_initialPosition(shape->absolutePosition(KoFlake::TopLeft))
33 , m_finalPos(m_initialPosition)
34 , m_anchorOffset(m_shape->absoluteTransformation().map(QPointF()))
35 , m_startHandle(start)
36{
40 if (std::optional<InlineSizeInfo> info = InlineSizeInfo::fromShape(shape)) {
41 m_initialInlineSize = m_finalInlineSize = info->inlineSize;
42 m_anchor = info->anchor;
43 m_handleSide = m_startHandle? info->startLineSide(): info->endLineSide();
44 QPointF handleLocation = m_startHandle? info->startLine().p1(): info->endLine().p1();
45 QTransform invTransform = (info->editorTransform * info->shapeTransform).inverted();
46 QPointF initPos = info->editorTransform.inverted().map(m_shape->initialTextPosition());
47 m_snapDelta = invTransform.inverted().map(QPointF(invTransform.map(handleLocation).x(), initPos.y())) - m_dragStart;
48 } else {
49 // We cannot bail out, so just pretend to be doing something :(
51 m_anchor = VisualAnchor::LeftOrTop;
52 m_handleSide = m_startHandle? Side::LeftOrTop: Side::RightOrBottom;
53 }
54}
55
56void SvgInlineSizeChangeStrategy::handleMouseMove(const QPointF &mouseLocation, Qt::KeyboardModifiers modifiers)
57{
58 QTransform invTransform{};
59 QPointF initPos;
60 if (std::optional<InlineSizeInfo> info = InlineSizeInfo::fromShape(m_shape)) {
61 invTransform = (info->editorTransform * info->shapeTransform).inverted();
62 initPos = info->editorTransform.inverted().map(m_shape->initialTextPosition());
63 }
64
65 double newInlineSize = 0.0;
66
67 QPointF snapDelta = invTransform.inverted().map(QPointF(invTransform.map(mouseLocation + m_snapDelta).x(), initPos.y())) - mouseLocation;
68 QPointF snappedLocation = tool()->canvas()->snapGuide()->snap(mouseLocation + snapDelta, modifiers) - snapDelta;
69 const double mouseDelta = invTransform.map(QLineF(m_dragStart, snappedLocation)).dx();
70 QPointF newPosition = m_shape->absolutePosition(KoFlake::TopLeft);
71
72 // The anchor pos is mostly to determine the transformed origin so that moving the position stays consistent.
73 QPointF anchorPos = m_shape->absoluteTransformation().map(QPointF());
74 QPointF anchorDiff = anchorPos - m_anchorOffset;
75 QPointF diff = (invTransform.inverted().map(QPointF(mouseDelta, 0)) - anchorPos) - anchorDiff;
76
77
78 switch (m_anchor) {
79 case VisualAnchor::LeftOrTop:
80 if (m_handleSide == Side::RightOrBottom) {
81 newInlineSize = m_initialInlineSize + mouseDelta;
82 } else {
83 newInlineSize = m_initialInlineSize - mouseDelta;
84 }
85 break;
86 case VisualAnchor::Mid:
87 if (modifiers.testFlag(Qt::ControlModifier)) {
88 if (m_handleSide == Side::RightOrBottom) {
89 newInlineSize = m_initialInlineSize + 2.0 * mouseDelta;
90 } else {
91 newInlineSize = m_initialInlineSize - 2.0 * mouseDelta;
92 }
93 diff = QPointF();
94 newPosition -= anchorDiff;
95 } else {
96 if (m_handleSide == Side::RightOrBottom) {
97 newInlineSize = m_initialInlineSize + mouseDelta;
98 newPosition += ((invTransform.inverted().map(QPointF(0.5 * mouseDelta, 0)) - anchorPos)) - anchorDiff;
99 } else {
100 newInlineSize = m_initialInlineSize - mouseDelta;
101 diff = ((invTransform.inverted().map(QPointF(0.5 * mouseDelta, 0)) - anchorPos)) - anchorDiff;
102 }
103 }
104 break;
105 case VisualAnchor::RightOrBottom:
106 if (m_handleSide == Side::LeftOrTop) {
107 newInlineSize = m_initialInlineSize - mouseDelta;
108 } else {
109 newInlineSize = m_initialInlineSize + mouseDelta;
110 }
111 break;
112 }
113
114 if (m_startHandle) {
115 newPosition += diff;
116 }
117
118 const bool flip = newInlineSize < -1.0;
119 if (newInlineSize >= -1.0 && newInlineSize < 1.0) {
120 newInlineSize = 1.0;
121 } else {
122 newInlineSize = qRound(newInlineSize * 100.0) / 100.0;
123
124 }
125
127 if (flip) {
128 newInlineSize = fabs(newInlineSize);
129 if (newAnchor == KoSvgText::AnchorStart) {
130 newAnchor = KoSvgText::AnchorEnd;
131 } else if (newAnchor == KoSvgText::AnchorEnd) {
132 newAnchor = KoSvgText::AnchorStart;
133 }
134 }
135 if (qFuzzyCompare(m_finalInlineSize, newInlineSize)
136 && m_initialPosition == newPosition
137 && m_originalAnchor == newAnchor) {
138 return;
139 }
141 newPosition, m_initialPosition).redo();
142
143 m_finalInlineSize = newInlineSize;
144 m_finalAnchor = newAnchor;
145 m_finalPos = newPosition;
147}
148
160
172
173void SvgInlineSizeChangeStrategy::finishInteraction(Qt::KeyboardModifiers /*modifiers*/)
174{
175}
KoSnapGuide * snapGuide
QPointF absolutePosition(KoFlake::AnchorPosition anchor=KoFlake::Center) const
Definition KoShape.cpp:653
QTransform absoluteTransformation() const
Definition KoShape.cpp:382
static QList< KoShape * > linearizeSubtree(const QList< KoShape * > &shapes)
Definition KoShape.cpp:1381
void reset()
Resets the snap guide.
QPointF snap(const QPointF &mousePosition, Qt::KeyboardModifiers modifiers)
snaps the mouse position, returns if mouse was snapped
void setIgnoredShapes(const QList< KoShape * > &ignoredShapes)
Sets list of ignored shapes.
@ TextAnchorId
KoSvgText::TextAnchor.
QVariant propertyOrDefault(PropertyId id) const
QPointF initialTextPosition
KoSvgTextProperties textProperties() const
KoCanvasBase * canvas() const
Returns the canvas the tool is working on.
virtual void repaintDecorations()
SvgInlineSizeHelper::VisualAnchor m_anchor
void finishInteraction(Qt::KeyboardModifiers modifiers) override
void handleMouseMove(const QPointF &mouseLocation, Qt::KeyboardModifiers modifiers) override
SvgInlineSizeChangeStrategy(KoToolBase *tool, KoSvgTextShape *shape, const QPointF &clicked, bool start)
SvgInlineSizeHelper::Side m_handleSide
static bool qFuzzyCompare(half p1, half p2)
@ TopLeft
Definition KoFlake.h:86
TextAnchor
Where the text is anchored for SVG 1.1 text and 'inline-size'.
Definition KoSvgText.h:79
@ AnchorEnd
Anchor right for LTR, left for RTL.
Definition KoSvgText.h:82
@ AnchorStart
Anchor left for LTR, right for RTL.
Definition KoSvgText.h:80
static double getInlineSizePt(const KoSvgTextShape *const shape)