Krita Source Code Documentation
Loading...
Searching...
No Matches
SvgTextLabel.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2024 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6#include "SvgTextLabel.h"
7#include <KoSvgTextShape.h>
9#include <KoColorBackground.h>
10#include <QPainter>
11#include <QQuickWindow>
12#include <KoShapePainter.h>
13#include <kis_assert.h>
14
15struct Q_DECL_HIDDEN SvgTextLabel::Private {
16
18 : shape(new KoSvgTextShape())
19 {
20 shape->setResolution(72, 72);
21 shape->setRelayoutBlocked(true);
22 shape->setFontMatchingDisabled(true);
23 }
25
26 QScopedPointer<KoSvgTextShape> shape;
27
32 QScopedPointer<KoShapePainter> shapePainter;
33
35
36 int topPadding = 2;
37 int bottomPadding = 2;
38 int leftPadding = 2;
39 int rightPadding = 2;
40
41 bool addedShapeToPainter = false; //Tests if the shape has been added to the painter yet.
42};
43
44SvgTextLabel::SvgTextLabel(QQuickItem *parent)
45 : QQuickPaintedItem(parent)
46 , d(new Private())
47{
48 setImplicitSize(10, 10);
49 setAntialiasing(true);
50 setOpaquePainting(true);
51
52 connect(this, SIGNAL(openTypeFeaturesChanged(QVariantMap)), this, SLOT(updateShape()));
53}
54
58
59void SvgTextLabel::paint(QPainter *painter)
60{
61 // the QML item must be finalized before paint() is called
62 KIS_SAFE_ASSERT_RECOVER_RETURN(d->shapePainter);
63
64 if (width() == 0 || height() == 0) return;
65 if (!painter->isActive()) return;
66 painter->save();
67 if (d->shape->boundingRect().isEmpty()) {
68 painter->restore();
69 return;
70 }
71
72 QRectF bbox = d->shape->selectionBoxes(0, d->shape->posForIndex(d->shape->plainText().size())).boundingRect();
73 bbox = bbox.isEmpty()? d->shape->boundingRect(): bbox;
74
75 // Scale padding so that it is relative to the width and height.
76 const double newWidth = width()-(d->leftPadding+d->rightPadding);
77 const double newLeftPadding = (d->leftPadding / newWidth) * bbox.width();
78 const double newRightPadding = (d->rightPadding / newWidth) * bbox.width();
79 const double newHeight = height()-(d->topPadding+d->bottomPadding);
80 const double newTopPadding = (d->topPadding / newHeight) * bbox.height();
81 const double newBottomPadding = (d->bottomPadding / newHeight) * bbox.height();
82
83 d->shapePainter->paint(*painter,
84 QRectF(0, 0, width(), height()).toAlignedRect(),
85 bbox.adjusted(-newLeftPadding, -newTopPadding, newRightPadding, newBottomPadding));
86 painter->restore();
87}
88
90{
91 return d->shape->textProperties().property(KoSvgTextProperties::FontFamiliesId).value<QStringList>();
92}
93
95{
96 return d->shape->textProperties().property(KoSvgTextProperties::FontWeightId).toReal();
97}
98
100{
101 return d->shape->textProperties().property(KoSvgTextProperties::FontStretchId).toReal();
102}
103
104QFont::Style SvgTextLabel::fontStyle() const
105{
106 return d->shape->textProperties().property(KoSvgTextProperties::FontStyleId).value<KoSvgText::CssFontStyleData>().style;
107}
108
110{
111 KoSvgText::CssFontStyleData style = d->shape->textProperties().property(KoSvgTextProperties::FontStyleId).value<KoSvgText::CssFontStyleData>();
112 return style.slantValue.isAuto? 14.0: style.slantValue.customValue;
113}
114
116{
117 return d->props.propertyOrDefault(KoSvgTextProperties::FontVariationSettingsId).toMap();
118}
119
121{
122 return d->shape->textProperties().property(KoSvgTextProperties::FontSizeId).toReal();
123}
124
126{
127 KoColorBackground *bg = dynamic_cast<KoColorBackground*>(d->shape->background().data());
128 if (bg) {
129 return bg->color();
130 }
131 return Qt::black;
132}
133
135{
136 return d->shape->textProperties().property(KoSvgTextProperties::FontFeatureSettingsId).toMap();
137}
138
139QString SvgTextLabel::text() const
140{
141 return d->shape->plainText();
142}
143
145{
146 return (d->leftPadding+d->rightPadding+d->topPadding+d->bottomPadding)/4;
147}
148
150{
151 return d->shape->textProperties().property(KoSvgTextProperties::TextLanguage).toString();
152}
153
155{
156 QStringList current = d->props.property(KoSvgTextProperties::FontFamiliesId).value<QStringList>();
157 if (current == fontFamilies)
158 return;
159
162}
163
164void SvgTextLabel::setFontWeight(qreal fontWeight)
165{
166 qreal current = d->props.property(KoSvgTextProperties::FontWeightId).toReal();
167 if (qFuzzyCompare(current, fontWeight))
168 return;
169
172}
173
174void SvgTextLabel::setFontWidth(qreal fontWidth)
175{
176 qreal current = d->props.property(KoSvgTextProperties::FontStretchId).toReal();
177 if (qFuzzyCompare(current, fontWidth))
178 return;
179
182}
183
184void SvgTextLabel::setFontStyle(QFont::Style fontStyle)
185{
187 if (current.style == fontStyle)
188 return;
189
190 current.style = fontStyle;
191 d->props.setProperty(KoSvgTextProperties::FontStyleId, QVariant::fromValue(current));
193}
194
195void SvgTextLabel::setFontSlant(qreal fontSlant)
196{
198 if (current.slantValue.isAuto && qFuzzyCompare(fontSlant, 14))
199 return;
200 if (!current.slantValue.isAuto && qFuzzyCompare(fontSlant, current.slantValue.customValue))
201 return;
202
204 current.slantValue.isAuto = false;
205 d->props.setProperty(KoSvgTextProperties::FontStyleId, QVariant::fromValue(current));
207}
208
209void SvgTextLabel::setFontAxesValues(QVariantMap fontAxesValues)
210{
211 QVariantMap current = d->props.property(KoSvgTextProperties::FontVariationSettingsId).toMap();
212 if (current == fontAxesValues)
213 return;
214
215 d->props.setProperty(KoSvgTextProperties::FontVariationSettingsId, QVariant::fromValue(fontAxesValues));
217}
218
219void SvgTextLabel::setFontSize(qreal fontSize)
220{
222 if (qFuzzyCompare(current.value, fontSize))
223 return;
224
225 current.value = fontSize;
226 d->props.setProperty(KoSvgTextProperties::FontSizeId, QVariant::fromValue(current));
228}
229
230void SvgTextLabel::setTextColor(QColor textColor)
231{
232 if (d->props.hasProperty(KoSvgTextProperties::FillId)) {
233 KoColorBackground *bg = dynamic_cast<KoColorBackground*>(d->shape->background().data());
234 if (bg) {
235 if (bg->color() == textColor)
236 return;
237 }
238 }
239
241 d->props.setProperty(KoSvgTextProperties::FillId, d->shape->textProperties().property(KoSvgTextProperties::FillId));
243 if (!opaquePainting() && isComponentComplete()) {
244 update(boundingRect().toAlignedRect());
245 }
246}
247
248void SvgTextLabel::setOpenTypeFeatures(QVariantMap openTypeFeatures)
249{
250 QVariantMap otf = d->props.property(KoSvgTextProperties::FontFeatureSettingsId).toMap();
251 if (otf == openTypeFeatures)
252 return;
253
254 d->props.setProperty(KoSvgTextProperties::FontFeatureSettingsId, QVariant::fromValue(openTypeFeatures));
256}
257
258void SvgTextLabel::setText(QString text)
259{
260 if (d->shape->plainText() == text)
261 return;
262
263 int length = d->shape->plainText().size();
264 int start = 0;
265 d->shape->removeText(start, length);
266 d->shape->insertText(0, text);
267 emit textChanged(d->shape->plainText());
268}
269
271{
272 const int currentPadding = (d->leftPadding+d->rightPadding+d->topPadding+d->bottomPadding)/4;
273 if (currentPadding == padding)
274 return;
275
276 d->leftPadding = padding;
277 d->rightPadding = padding;
278 d->topPadding = padding;
279 d->bottomPadding = padding;
281 emit minimumRectChanged();
282}
283
284void SvgTextLabel::setLanguage(QString language)
285{
286 const QString lang = d->props.property(KoSvgTextProperties::TextLanguage).toString();
287 if (lang == language) {
288 return;
289 }
290 d->props.setProperty(KoSvgTextProperties::TextLanguage, language);
292}
293
295{
296 QQuickPaintedItem::componentComplete();
297
298 if (this->window()) {
299 const qreal pixelRatio = this->window()->effectiveDevicePixelRatio();
300 d->shape->setResolution(pixelRatio*72, pixelRatio*72);
301 }
302 setOpaquePainting(fillColor().alpha() == 255);
303 if (!d->shapePainter) {
304 d->shapePainter.reset(new KoShapePainter());
305 if (!d->shape->boundingRect().isEmpty()) {
306 d->shapePainter->setShapes({d->shape.data()});
307 d->addedShapeToPainter = true;
308 }
309 }
310 updateShape();
311}
312
314{
315 if (d->shape) {
316 const QRectF bbox = d->shape->selectionBoxes(0, d->shape->posForIndex(d->shape->plainText().size())).boundingRect();
317 return bbox.adjusted(-d->leftPadding, -d->topPadding, d->rightPadding, d->bottomPadding);
318 }
319 return QRectF();
320}
321
323{
324 if (d->shape->textProperties() == d->props) {
325 return;
326 }
327 d->shape->setPropertiesAtPos(-1, d->props);
328 d->shape->relayout();
329 if (!d->addedShapeToPainter && d->shapePainter && !d->shape->boundingRect().isEmpty()) {
330 d->shapePainter->setShapes({d->shape.data()});
331 d->addedShapeToPainter = true;
332 }
333 if (isVisible()) {
334 update(boundingRect().toAlignedRect());
335 }
336 emit minimumRectChanged();
337}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
A simple solid color shape background.
QColor color() const
Returns the background color.
@ FillId
KoSvgText::BackgroundProperty.
@ FontStyleId
KoSvgText::CssSlantData.
@ FontFeatureSettingsId
QStringList.
@ FontVariationSettingsId
QStringList.
@ TextLanguage
a language string.
static bool qFuzzyCompare(half p1, half p2)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
When style is oblique, a custom slant value can be specified for variable fonts.
Definition KoSvgText.h:475
KoSvgText::AutoValue slantValue
Definition KoSvgText.h:479
SvgTextLabel(QQuickItem *parent=nullptr)
QScopedPointer< KoSvgTextShape > shape
void setFontSize(qreal fontSize)
void setFontStyle(QFont::Style fontStyle)
void fontWidthChanged(qreal fontWidth)
void languageChanged(QString language)
void fontFamiliesChanged(QStringList)
void setFontWeight(qreal fontWeight)
void fontWeightChanged(qreal fontWeight)
void minimumRectChanged()
QColor textColor
QRectF minimumRect
QFont::Style fontStyle
QVariantMap fontAxesValues
void setLanguage(QString language)
void setOpenTypeFeatures(QVariantMap openTypeFeatures)
void setFontFamilies(QStringList fontFamilies)
QScopedPointer< KoShapePainter > shapePainter
KoSvgTextProperties props
void setTextColor(QColor textColor)
void fontSlantChanged(qreal fontSlant)
void fontStyleChanged(QFont::Style fontStyle)
void textColorChanged(QColor textColor)
QML_ELEMENTQStringList fontFamilies
void setPadding(int padding)
void setFontAxesValues(QVariantMap fontAxesValues)
const QScopedPointer< Private > d
void fontAxesValuesChanged(QVariantMap fontAxesValues)
void paint(QPainter *painter) override
void setText(QString text)
void fontSizeChanged(qreal fontSize)
void textChanged(QString text)
void componentComplete() override
componentComplete called when all properties have been set. used to avoid relayout being called time ...
void setFontSlant(qreal fontSlant)
QVariantMap openTypeFeatures
void openTypeFeaturesChanged(QVariantMap openTypeFeatures)
void setFontWidth(qreal fontWidth)
void paddingChanged(int padding)
QString language