Krita Source Code Documentation
Loading...
Searching...
No Matches
KoStopGradient.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2005 Tim Beaulen <tbscope@gmail.org>
3 SPDX-FileCopyrightText: 2007 Jan Hambrecht <jaham@gmx.net>
4 SPDX-FileCopyrightText: 2007 Sven Langkamp <sven.langkamp@gmail.com>
5 SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me>
6
7 SPDX-License-Identifier: LGPL-2.1-or-later
8 */
9
11
12#include <array>
13#include <cfloat>
14#include <cmath>
15
16#include <QColor>
17#include <QFile>
18#include <QDomDocument>
19#include <QDomElement>
20#include <QBuffer>
21
22#include <klocalizedstring.h>
23#include <DebugPigment.h>
24
26#include <KoColorSpaceEngine.h>
27#include <KoColorProfile.h>
28#include "KoMixColorsOp.h"
29
30#include "kis_dom_utils.h"
31
33#include <KoXmlNS.h>
34
37
38
39KoStopGradient::KoStopGradient(const QString& filename)
40 : KoAbstractGradient(filename)
41{
42}
43
47
50 , m_stops(rhs.m_stops)
51 , m_start(rhs.m_start)
52 , m_stop(rhs.m_stop)
53 , m_focalPoint(rhs.m_focalPoint)
54{
55}
56
58{
59 return
60 *colorSpace() == *rhs.colorSpace() &&
61 spread() == rhs.spread() &&
62 type() == rhs.type() &&
63 m_start == rhs.m_start &&
64 m_stop == rhs.m_stop &&
66 m_stops == rhs.m_stops;
67}
68
70{
71 return KoResourceSP(new KoStopGradient(*this));
72}
73
74bool KoStopGradient::loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP resourcesInterface)
75{
76 Q_UNUSED(resourcesInterface);
77 loadSvgGradient(dev);
78 if (m_stops.count() >= 2) {
79 setValid(true);
80 }
82 return true;
83}
84
86{
87 QGradient* gradient;
88
89 switch (type()) {
90 case QGradient::LinearGradient: {
91 gradient = new QLinearGradient(m_start, m_stop);
92 break;
93 }
94 case QGradient::RadialGradient: {
95 QPointF diff = m_stop - m_start;
96 qreal radius = sqrt(diff.x() * diff.x() + diff.y() * diff.y());
97 gradient = new QRadialGradient(m_start, radius, m_focalPoint);
98 break;
99 }
100 case QGradient::ConicalGradient: {
101 qreal angle = atan2(m_start.y(), m_start.x()) * 180.0 / M_PI;
102 if (angle < 0.0)
103 angle += 360.0;
104 gradient = new QConicalGradient(m_start, angle);
105 break;
106 }
107 default:
108 return 0;
109 }
110 QColor color;
111 for (QList<KoGradientStop>::const_iterator i = m_stops.begin(); i != m_stops.end(); ++i) {
112 i->color.toQColor(&color);
113 gradient->setColorAt(i->position, color);
114 }
115
116 gradient->setCoordinateMode(QGradient::ObjectBoundingMode);
117 gradient->setSpread(this->spread());
118
119 return gradient;
120}
121
122bool KoStopGradient::stopsAt(KoGradientStop& leftStop, KoGradientStop& rightStop, qreal t) const
123{
124 if (!m_stops.count())
125 return false;
126
127 KIS_SAFE_ASSERT_RECOVER(!qIsNaN(t)) { // if it's nan, it would crash in the last 'else'
128 leftStop = m_stops.first();
129 rightStop = KoGradientStop(-std::numeric_limits<double>::infinity(), leftStop.color, leftStop.type);
130 return true;
131 }
132
133 if (t <= m_stops.first().position || m_stops.count() == 1) {
134 // we have only one stop or t is before the first stop
135 leftStop = m_stops.first();
136 rightStop = KoGradientStop(-std::numeric_limits<double>::infinity(), leftStop.color, leftStop.type);
137 return true;
138 } else if (t >= m_stops.last().position) {
139 // t is after the last stop
140 rightStop = m_stops.last();
141 leftStop = KoGradientStop(std::numeric_limits<double>::infinity(), rightStop.color, rightStop.type);
142 return true;
143 } else {
144 // we have at least two color stops
145 // -> find the two stops which frame our t
146 auto it = std::lower_bound(m_stops.begin(), m_stops.end(), KoGradientStop(t, KoColor(), COLORSTOP),
148 leftStop = *(it - 1);
149 rightStop = *(it);
150 return true;
151 }
152}
153
154void KoStopGradient::colorAt(KoColor& dst, qreal t) const
155{
156 KoGradientStop leftStop, rightStop;
157 if (!stopsAt(leftStop, rightStop, t)) return;
158
159 const KoColorSpace *mixSpace = dst.colorSpace();
160
161 KoColor buffer(mixSpace);
162 KoColor startDummy(leftStop.color, mixSpace);
163 KoColor endDummy(rightStop.color, mixSpace);
164
165 const std::array<quint8 *, 2> colors = {{startDummy.data(), endDummy.data()}};
166
167 qreal localT = NAN;
168 qreal stopDistance = rightStop.position - leftStop.position;
169 if (stopDistance < DBL_EPSILON) {
170 localT = 0.5;
171 } else {
172 localT = (t - leftStop.position) / stopDistance;
173 }
174 std::array<qint16, 2> colorWeights {};
175 colorWeights[0] = std::lround((1.0 - localT) * qint16_MAX);
176 colorWeights[1] = qint16_MAX - colorWeights[0];
177
178 mixSpace->mixColorsOp()->mixColors(colors.data(), colorWeights.data(), 2, buffer.data(), qint16_MAX);
179
180 dst = buffer;
181}
182
184{
185 if (!gradient)
187
188 QSharedPointer<KoStopGradient> newGradient(new KoStopGradient(QString()));
189 newGradient->setType(gradient->type());
190 newGradient->setSpread(gradient->spread());
191
192 switch (gradient->type()) {
193 case QGradient::LinearGradient: {
194 const QLinearGradient* g = static_cast<const QLinearGradient*>(gradient);
195 newGradient->m_start = g->start();
196 newGradient->m_stop = g->finalStop();
197 newGradient->m_focalPoint = g->start();
198 break;
199 }
200 case QGradient::RadialGradient: {
201 const QRadialGradient* g = static_cast<const QRadialGradient*>(gradient);
202 newGradient->m_start = g->center();
203 newGradient->m_stop = g->center() + QPointF(g->radius(), 0);
204 newGradient->m_focalPoint = g->focalPoint();
205 break;
206 }
207 case QGradient::ConicalGradient: {
208 const QConicalGradient* g = static_cast<const QConicalGradient*>(gradient);
209 qreal radian = g->angle() * M_PI / 180.0;
210 newGradient->m_start = g->center();
211 newGradient->m_stop = QPointF(100.0 * cos(radian), 100.0 * sin(radian));
212 newGradient->m_focalPoint = g->center();
213 break;
214 }
215 default:
217 }
218
219 Q_FOREACH(const QGradientStop & stop, gradient->stops()) {
220 KoColor color(newGradient->colorSpace());
221 color.fromQColor(stop.second);
222 newGradient->m_stops.append(KoGradientStop(stop.first, color, COLORSTOP));
223 }
224
225 newGradient->setValid(true);
226
227 return newGradient;
228}
229
231{
232 m_stops.clear();
233 m_hasVariableStops = false;
234 KoColor color;
235 Q_FOREACH(const KoGradientStop & stop, stops) {
236 color = stop.color;
237 m_stops.append(KoGradientStop(stop.position, color, stop.type));
238 if (stop.type != COLORSTOP) {
239 m_hasVariableStops = true;
240 }
241 }
242 if (m_stops.count() >= 2) {
243 setValid(true);
244 } else {
245 setValid(false);
246 }
248}
249
254
256{
257 QList<int> result;
258
259 if (std::find_if_not(m_stops.begin(), m_stops.end(),
261 != m_stops.end()) {
262
264 }
265
266 return result;
267}
268
270{
271 const KoColor fgColor = canvasResourcesInterface->resource(KoCanvasResource::ForegroundColor).value<KoColor>();
272 const KoColor bgColor = canvasResourcesInterface->resource(KoCanvasResource::BackgroundColor).value<KoColor>();
273
274 for (auto it = m_stops.begin(); it != m_stops.end(); ++it) {
275 if (it->type == FOREGROUNDSTOP) {
276 it->color = fgColor;
277 it->type = COLORSTOP;
278 } else if (it->type == BACKGROUNDSTOP) {
279 it->color = bgColor;
280 it->type = COLORSTOP;
281 }
282 }
283}
284
286{
287 const KoColor fgColor = canvasResourcesInterface->resource(KoCanvasResource::ForegroundColor).value<KoColor>();
288 const KoColor bgColor = canvasResourcesInterface->resource(KoCanvasResource::BackgroundColor).value<KoColor>();
289
290 for (auto it = m_stops.begin(); it != m_stops.end(); ++it) {
291 if (it->type == FOREGROUNDSTOP) {
292 it->color = fgColor;
293 } else if (it->type == BACKGROUNDSTOP) {
294 it->color = bgColor;
295 }
296 }
297}
298
300{
301 QDomDocument doc;
302
303 if (!(doc.setContent(file))) {
304 file->close();
305 } else {
306 QHash<QString, const KoColorProfile*> profiles;
307 for (QDomElement e = doc.documentElement().firstChildElement("defs"); !e.isNull(); e = e.nextSiblingElement("defs")) {
308 for (QDomElement profileEl = e.firstChildElement("color-profile"); !profileEl.isNull(); profileEl = profileEl.nextSiblingElement("color-profile")) {
309 const QString href = profileEl.attribute("xlink:href");
310 const QByteArray uniqueId = QByteArray::fromHex(profileEl.attribute("local").toLatin1());
311 const QString name = profileEl.attribute("name");
312
313 const KoColorProfile *profile =
315 if (!profile) {
316 QFile file(href);
317 if (file.exists()) {
319 KIS_ASSERT(engine);
320 file.open(QIODevice::ReadOnly);
321 const QByteArray profileData = file.readAll();
322 if (!profileData.isEmpty()) {
323 profile = engine->addProfile(href);
324 }
325 }
326 }
327
328
329 if (profile && !profiles.contains(name)) {
330 profiles.insert(name, profile);
331 }
332 }
333 }
334 for (QDomNode n = doc.documentElement().firstChild(); !n.isNull(); n = n.nextSibling()) {
335 QDomElement e = n.toElement();
336
337 if (e.isNull()) continue;
338
339 if (e.tagName() == "linearGradient" || e.tagName() == "radialGradient") {
340 parseSvgGradient(e, profiles);
341 return;
342 }
343 // Inkscape gradients are in another defs
344 if (e.tagName() == "defs") {
345
346
347 for (QDomNode defnode = e.firstChild(); !defnode.isNull(); defnode = defnode.nextSibling()) {
348 QDomElement defelement = defnode.toElement();
349
350 if (defelement.isNull()) continue;
351
352 if (defelement.tagName() == "linearGradient" || defelement.tagName() == "radialGradient") {
353 parseSvgGradient(defelement, profiles);
354 return;
355 }
356 }
357 }
358 }
359 }
360}
361
362
363void KoStopGradient::parseSvgGradient(const QDomElement& element, QHash<QString, const KoColorProfile *> profiles)
364{
365 m_stops.clear();
366 m_hasVariableStops = false;
367 setSpread(QGradient::PadSpread);
368
369 /*QString href = e.attribute( "xlink:href" ).mid( 1 );
370 if( !href.isEmpty() )
371 {
372 }*/
373 setName(element.attribute("id", i18n("SVG Gradient")));
374
375 bool bbox = element.attribute("gradientUnits") != "userSpaceOnUse";
376
377 if (element.tagName() == "linearGradient") {
378
379 if (bbox) {
380 QString s;
381
382 s = element.attribute("x1", "0%");
383 qreal xOrigin;
384 if (s.endsWith('%'))
385 xOrigin = s.remove('%').toDouble();
386 else
387 xOrigin = s.toDouble() * 100.0;
388
389 s = element.attribute("y1", "0%");
390 qreal yOrigin;
391 if (s.endsWith('%'))
392 yOrigin = s.remove('%').toDouble();
393 else
394 yOrigin = s.toDouble() * 100.0;
395
396 s = element.attribute("x2", "100%");
397 qreal xVector;
398 if (s.endsWith('%'))
399 xVector = s.remove('%').toDouble();
400 else
401 xVector = s.toDouble() * 100.0;
402
403 s = element.attribute("y2", "0%");
404 qreal yVector;
405 if (s.endsWith('%'))
406 yVector = s.remove('%').toDouble();
407 else
408 yVector = s.toDouble() * 100.0;
409
410 m_start = QPointF(xOrigin, yOrigin);
411 m_stop = QPointF(xVector, yVector);
412 }
413 else {
414 m_start = QPointF(element.attribute("x1").toDouble(), element.attribute("y1").toDouble());
415 m_stop = QPointF(element.attribute("x2").toDouble(), element.attribute("y2").toDouble());
416 }
417 setType(QGradient::LinearGradient);
418 }
419 else {
420 if (bbox) {
421 QString s;
422
423 s = element.attribute("cx", "50%");
424 qreal xOrigin;
425 if (s.endsWith('%'))
426 xOrigin = s.remove('%').toDouble();
427 else
428 xOrigin = s.toDouble() * 100.0;
429
430 s = element.attribute("cy", "50%");
431 qreal yOrigin;
432 if (s.endsWith('%'))
433 yOrigin = s.remove('%').toDouble();
434 else
435 yOrigin = s.toDouble() * 100.0;
436
437 s = element.attribute("cx", "50%");
438 qreal xVector;
439 if (s.endsWith('%'))
440 xVector = s.remove('%').toDouble();
441 else
442 xVector = s.toDouble() * 100.0;
443
444 s = element.attribute("r", "50%");
445 if (s.endsWith('%'))
446 xVector += s.remove('%').toDouble();
447 else
448 xVector += s.toDouble() * 100.0;
449
450 s = element.attribute("cy", "50%");
451 qreal yVector;
452 if (s.endsWith('%'))
453 yVector = s.remove('%').toDouble();
454 else
455 yVector = s.toDouble() * 100.0;
456
457 s = element.attribute("fx", "50%");
458 qreal xFocal;
459 if (s.endsWith('%'))
460 xFocal = s.remove('%').toDouble();
461 else
462 xFocal = s.toDouble() * 100.0;
463
464 s = element.attribute("fy", "50%");
465 qreal yFocal;
466 if (s.endsWith('%'))
467 yFocal = s.remove('%').toDouble();
468 else
469 yFocal = s.toDouble() * 100.0;
470
471 m_start = QPointF(xOrigin, yOrigin);
472 m_stop = QPointF(xVector, yVector);
473 m_focalPoint = QPointF(xFocal, yFocal);
474 }
475 else {
476 m_start = QPointF(element.attribute("cx").toDouble(), element.attribute("cy").toDouble());
477 m_stop = QPointF(element.attribute("cx").toDouble() + element.attribute("r").toDouble(),
478 element.attribute("cy").toDouble());
479 m_focalPoint = QPointF(element.attribute("fx").toDouble(), element.attribute("fy").toDouble());
480 }
481 setType(QGradient::RadialGradient);
482 }
483 // handle spread method
484 QString spreadMethod = element.attribute("spreadMethod");
485 if (!spreadMethod.isEmpty()) {
486 if (spreadMethod == "reflect")
487 setSpread(QGradient::ReflectSpread);
488 else if (spreadMethod == "repeat")
489 setSpread(QGradient::RepeatSpread);
490 }
491
492 for (QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling()) {
493 QDomElement colorstop = n.toElement();
494 if (colorstop.tagName() == "stop") {
495 qreal opacity = 0.0;
496 KoColor color;
497 float off;
498 QString temp = colorstop.attribute("offset");
499 if (temp.contains('%')) {
500 temp = temp.left(temp.length() - 1);
501 off = temp.toFloat() / 100.0;
502 }
503 else
504 off = temp.toFloat();
505
506 if (!colorstop.attribute("stop-color").isEmpty())
507 color = KoColor::fromSVG11(colorstop.attribute("stop-color"), profiles);
508 else {
509 // try style attr
510 QString style = colorstop.attribute("style").simplified();
511 QStringList substyles = style.split(';', Qt::SkipEmptyParts);
512 Q_FOREACH(const QString & s, substyles) {
513 QStringList substyle = s.split(':');
514 QString command = substyle[0].trimmed();
515 QString params = substyle[1].trimmed();
516 if (command == "stop-color")
517 color = KoColor::fromSVG11(params, profiles);
518 if (command == "stop-opacity")
519 opacity = params.toDouble();
520 }
521
522 }
523 if (!colorstop.attribute("stop-opacity").isEmpty())
524 opacity = colorstop.attribute("stop-opacity").toDouble();
525
526 color.setOpacity(static_cast<quint8>(std::lround(opacity * OPACITY_OPAQUE_U8)));
527 QString stopTypeStr = colorstop.attribute("krita:stop-type", "color-stop");
529 if (stopType != COLORSTOP) {
530 m_hasVariableStops = true;
531 }
532 //According to the SVG spec each gradient offset has to be equal to or greater than the previous one
533 //if not it needs to be adjusted to be equal
534 if (m_stops.count() > 0 && m_stops.last().position >= off) {
535 off = m_stops.last().position;
536 }
537 m_stops.append(KoGradientStop(off, color, stopType));
538 }
539 }
540 if (m_stops.count() >= 2) {
541 setValid(true);
542 } else {
543 setValid(false);
544 }
545}
546
548{
549 return QString(".svg");
550}
551
552void KoStopGradient::toXML(QDomDocument& doc, QDomElement& gradientElt) const
553{
554 gradientElt.setAttribute("type", "stop");
555 for (int s = 0; s < m_stops.size(); s++) {
556 KoGradientStop stop = m_stops.at(s);
557 QDomElement stopElt = doc.createElement("stop");
558 stopElt.setAttribute("offset", KisDomUtils::toString(stop.position));
559 stopElt.setAttribute("bitdepth", stop.color.colorSpace()->colorDepthId().id());
560 stopElt.setAttribute("alpha", KisDomUtils::toString(stop.color.opacityF()));
561 stopElt.setAttribute("stoptype", KisDomUtils::toString(stop.type));
562 stop.color.toXML(doc, stopElt);
563 gradientElt.appendChild(stopElt);
564 }
565}
566
568{
569 KoStopGradient gradient;
571 QDomElement stopElt = elt.firstChildElement("stop");
572 while (!stopElt.isNull()) {
573 qreal offset = KisDomUtils::toDouble(stopElt.attribute("offset", "0.0"));
574 QString bitDepth = stopElt.attribute("bitdepth", Integer8BitsColorDepthID.id());
575 KoColor color = KoColor::fromXML(stopElt.firstChildElement(), bitDepth);
576 color.setOpacity(KisDomUtils::toDouble(stopElt.attribute("alpha", "1.0")));
577 KoGradientStopType stoptype = static_cast<KoGradientStopType>(KisDomUtils::toInt(stopElt.attribute("stoptype", "0")));
578 stops.append(KoGradientStop(offset, color, stoptype));
579 stopElt = stopElt.nextSiblingElement("stop");
580 }
581 gradient.setStops(stops);
582 return gradient;
583}
584
586{
587 QDomDocument doc;
588
589 doc.setContent(QString("<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:krita=\"%1\" > </svg>").arg(KoXmlNS::krita));
590
591 const QString spreadMethod[3] = {
592 QString("pad"),
593 QString("reflect"),
594 QString("repeat")
595 };
596
597 QDomElement gradient = doc.createElement("linearGradient");
598 gradient.setAttribute("id", name());
599 gradient.setAttribute("gradientUnits", "objectBoundingBox");
600 gradient.setAttribute("spreadMethod", spreadMethod[spread()]);
601
602 QHash<QString, const KoColorProfile*> profiles;
603 for(const KoGradientStop & stop: m_stops) {
604 QDomElement stopEl = doc.createElement("stop");
605 stopEl.setAttribute("stop-color", stop.color.toSVG11(&profiles));
606 stopEl.setAttribute("offset", QString().setNum(stop.position));
607 stopEl.setAttribute("stop-opacity", stop.color.opacityF());
608 stopEl.setAttribute("krita:stop-type", stop.typeString());
609 gradient.appendChild(stopEl);
610 }
611
612 if (profiles.size()>0) {
613 QDomElement defs = doc.createElement("defs");
614 for (QString key: profiles.keys()) {
615 const KoColorProfile * profile = profiles.value(key);
616
617 QDomElement profileEl = doc.createElement("color-profile");
618 profileEl.setAttribute("name", key);
619 QString val = profile->uniqueId().toHex();
620 profileEl.setAttribute("local", val);
621 profileEl.setAttribute("xlink:href", profile->fileName());
622 defs.appendChild(profileEl);
623 }
624 doc.documentElement().appendChild(defs);
625 }
626
627 doc.documentElement().appendChild(gradient);
628
629 return doc.toString();
630}
631
632bool KoStopGradient::saveToDevice(QIODevice* dev) const
633{
634 QTextStream stream(dev);
636 stream << saveSvgGradient();
637
638 return true;
639}
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const quint8 OPACITY_OPAQUE_U8
KoGradientStopType
@ FOREGROUNDSTOP
@ BACKGROUNDSTOP
@ COLORSTOP
static KoColorSpaceEngineRegistry * instance()
virtual KoID colorDepthId() const =0
KoMixColorsOp * mixColorsOp
static KoColor fromSVG11(const QString value, QHash< QString, const KoColorProfile * > profileList, KoColor current=KoColor())
fromSVG11 Parses a color attribute value and returns a KoColor. SVG defines the colorprofiles elsewhe...
Definition KoColor.cpp:534
qreal opacityF() const
Definition KoColor.cpp:345
static KoColor fromXML(const QDomElement &elt, const QString &channelDepthId)
Definition KoColor.cpp:350
void toXML(QDomDocument &doc, QDomElement &colorElt) const
Definition KoColor.cpp:304
void setOpacity(quint8 alpha)
Definition KoColor.cpp:333
void fromQColor(const QColor &c)
Convenient function for converting from a QColor.
Definition KoColor.cpp:213
quint8 * data()
Definition KoColor.h:144
const KoColorSpace * colorSpace() const
return the current colorSpace
Definition KoColor.h:82
T get(const QString &id) const
QString id() const
Definition KoID.cpp:63
virtual void mixColors(const quint8 *const *colors, const qint16 *weights, int nColors, quint8 *dst, int weightSum=255) const =0
static QSharedPointer< KoStopGradient > fromQGradient(const QGradient *gradient)
Creates KoStopGradient from a QGradient.
void loadSvgGradient(QIODevice *file)
QString saveSvgGradient() const
QGradient * toQGradient() const override
reimplemented
QString defaultFileExtension() const override
reimplemented
bool stopsAt(KoGradientStop &leftStop, KoGradientStop &rightStop, qreal t) const
Find stops surrounding position, returns false if position outside gradient.
QList< KoGradientStop > m_stops
void colorAt(KoColor &, qreal t) const override
reimplemented
KoResourceSP clone() const override
bool loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP resourcesInterface) override
QList< int > requiredCanvasResources() const override
void updateVariableColors(KoCanvasResourcesInterfaceSP canvasResourcesInterface) override
bool saveToDevice(QIODevice *dev) const override
void parseSvgGradient(const QDomElement &element, QHash< QString, const KoColorProfile * > profiles)
void setStops(QList< KoGradientStop > stops)
Sets the gradient stops.
void toXML(QDomDocument &doc, QDomElement &gradientElt) const
toXML Convert the gradient to an XML string.
bool operator==(const KoStopGradient &rhs) const
void bakeVariableColors(KoCanvasResourcesInterfaceSP canvasResourcesInterface) override
static KoStopGradient fromXML(const QDomElement &elt)
fromXML convert a gradient from xml.
KoStopGradient(const QString &filename=QString())
~KoStopGradient() override
QList< KoGradientStop > stops() const
static const QString krita
Definition KoXmlNS.h:48
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
const qint16 qint16_MAX
Definition kis_global.h:28
#define M_PI
Definition kis_global.h:111
QSharedPointer< KoResource > KoResourceSP
double toDouble(const QString &str, bool *ok=nullptr)
int toInt(const QString &str, bool *ok=nullptr)
QString toString(const QString &value)
void setUtf8OnStream(QTextStream &stream)
@ BackgroundColor
The active background color selected for this canvas.
@ ForegroundColor
The active foreground color selected for this canvas.
auto mem_equal_to(MemTypeNoRef Class::*ptr, MemType &&value)
mem_equal_to is an unary functor that compares a member of the object to a given value
Definition KisMpl.h:233
auto mem_less(MemTypeNoRef Class::*ptr, MemType &&value)
mem_less is an unary functor that compares a member of the object to a given value
Definition KisMpl.h:269
void setSpread(QGradient::Spread spreadMethod)
const KoColorSpace * colorSpace
QGradient::Spread spread
void setType(QGradient::Type repeatType)
virtual QByteArray uniqueId() const =0
virtual const KoColorProfile * addProfile(const QString &filename)=0
static KoColorSpaceRegistry * instance()
const KoColorProfile * profileByUniqueId(const QByteArray &id) const
KoGradientStopType type
static KoGradientStopType typeFromString(QString typestring)
void setValid(bool valid)
void setName(const QString &name)
QString name