Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtgradientutils.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6#include <QtGui/QLinearGradient>
7#include <QtGui/QRadialGradient>
8#include <QtGui/QConicalGradient>
9#include <QtXml/QDomDocument>
10#include <QtCore/QDebug>
11
13
14using namespace Qt::StringLiterals;
15
16static QString gradientTypeToString(QGradient::Type type)
17{
18 if (type == QGradient::LinearGradient)
19 return "LinearGradient"_L1;
20 if (type == QGradient::RadialGradient)
21 return "RadialGradient"_L1;
22 if (type == QGradient::ConicalGradient)
23 return "ConicalGradient"_L1;
24 return "NoGradient"_L1;
25}
26
27static QGradient::Type stringToGradientType(const QString &name)
28{
29 if (name == "LinearGradient"_L1)
30 return QGradient::LinearGradient;
31 if (name == "RadialGradient"_L1)
32 return QGradient::RadialGradient;
33 if (name == "ConicalGradient"_L1)
34 return QGradient::ConicalGradient;
35 return QGradient::NoGradient;
36}
37
38static QString gradientSpreadToString(QGradient::Spread spread)
39{
40 if (spread == QGradient::PadSpread)
41 return "PadSpread"_L1;
42 if (spread == QGradient::RepeatSpread)
43 return "RepeatSpread"_L1;
44 if (spread == QGradient::ReflectSpread)
45 return "ReflectSpread"_L1;
46 return "PadSpread"_L1;
47}
48
49static QGradient::Spread stringToGradientSpread(const QString &name)
50{
51 if (name == "PadSpread"_L1)
52 return QGradient::PadSpread;
53 if (name == "RepeatSpread"_L1)
54 return QGradient::RepeatSpread;
55 if (name == "ReflectSpread"_L1)
56 return QGradient::ReflectSpread;
57 return QGradient::PadSpread;
58}
59
60static QString gradientCoordinateModeToString(QGradient::CoordinateMode mode)
61{
62 if (mode == QGradient::LogicalMode)
63 return "LogicalMode"_L1;
64 if (mode == QGradient::StretchToDeviceMode)
65 return "StretchToDeviceMode"_L1;
66 if (mode == QGradient::ObjectBoundingMode)
67 return "ObjectBoundingMode"_L1;
68 return "StretchToDeviceMode"_L1;
69}
70
72{
73 if (name == "LogicalMode"_L1)
74 return QGradient::LogicalMode;
75 if (name == "StretchToDeviceMode"_L1)
76 return QGradient::StretchToDeviceMode;
77 if (name == "ObjectBoundingMode"_L1)
78 return QGradient::ObjectBoundingMode;
79 return QGradient::StretchToDeviceMode;
80}
81
82static QDomElement saveColor(QDomDocument &doc, QColor color)
83{
84 QDomElement colorElem = doc.createElement("colorData"_L1);
85
86 colorElem.setAttribute("r"_L1, QString::number(color.red()));
87 colorElem.setAttribute("g"_L1, QString::number(color.green()));
88 colorElem.setAttribute("b"_L1, QString::number(color.blue()));
89 colorElem.setAttribute("a"_L1, QString::number(color.alpha()));
90
91 return colorElem;
92}
93
94static QDomElement saveGradientStop(QDomDocument &doc, const QGradientStop &stop)
95{
96 QDomElement stopElem = doc.createElement("stopData"_L1);
97
98 stopElem.setAttribute("position"_L1, QString::number(stop.first));
99
100 const QDomElement colorElem = saveColor(doc, stop.second);
101 stopElem.appendChild(colorElem);
102
103 return stopElem;
104}
105
106static QDomElement saveGradient(QDomDocument &doc, const QGradient &gradient)
107{
108 QDomElement gradElem = doc.createElement("gradientData"_L1);
109
110 const QGradient::Type type = gradient.type();
111 gradElem.setAttribute("type"_L1, gradientTypeToString(type));
112 gradElem.setAttribute("spread"_L1, gradientSpreadToString(gradient.spread()));
113 gradElem.setAttribute("coordinateMode"_L1, gradientCoordinateModeToString(gradient.coordinateMode()));
114
115 const QGradientStops stops = gradient.stops();
116 for (const QGradientStop &stop : stops)
117 gradElem.appendChild(saveGradientStop(doc, stop));
118
119 if (type == QGradient::LinearGradient) {
120 const QLinearGradient &g = *static_cast<const QLinearGradient *>(&gradient);
121 gradElem.setAttribute("startX"_L1, QString::number(g.start().x()));
122 gradElem.setAttribute("startY"_L1, QString::number(g.start().y()));
123 gradElem.setAttribute("endX"_L1, QString::number(g.finalStop().x()));
124 gradElem.setAttribute("endY"_L1, QString::number(g.finalStop().y()));
125 } else if (type == QGradient::RadialGradient) {
126 const QRadialGradient &g = *static_cast<const QRadialGradient *>(&gradient);
127 gradElem.setAttribute("centerX"_L1, QString::number(g.center().x()));
128 gradElem.setAttribute("centerY"_L1, QString::number(g.center().y()));
129 gradElem.setAttribute("focalX"_L1, QString::number(g.focalPoint().x()));
130 gradElem.setAttribute("focalY"_L1, QString::number(g.focalPoint().y()));
131 gradElem.setAttribute("radius"_L1, QString::number(g.radius()));
132 } else if (type == QGradient::ConicalGradient) {
133 const QConicalGradient &g = *static_cast<const QConicalGradient*>(&gradient);
134 gradElem.setAttribute("centerX"_L1, QString::number(g.center().x()));
135 gradElem.setAttribute("centerY"_L1, QString::number(g.center().y()));
136 gradElem.setAttribute("angle"_L1, QString::number(g.angle()));
137 }
138
139 return gradElem;
140}
141
142static QColor loadColor(const QDomElement &elem)
143{
144 if (elem.tagName() != "colorData"_L1)
145 return QColor();
146
147 return QColor(elem.attribute("r"_L1).toInt(),
148 elem.attribute("g"_L1).toInt(),
149 elem.attribute("b"_L1).toInt(),
150 elem.attribute("a"_L1).toInt());
151}
152
153static QGradientStop loadGradientStop(const QDomElement &elem)
154{
155 if (elem.tagName() != "stopData"_L1)
156 return QGradientStop();
157
158 const qreal pos = static_cast<qreal>(elem.attribute("position"_L1).toDouble());
159 return std::make_pair(pos, loadColor(elem.firstChild().toElement()));
160}
161
162static QGradient loadGradient(const QDomElement &elem)
163{
164 if (elem.tagName() != "gradientData"_L1)
165 return QLinearGradient();
166
167 const QGradient::Type type = stringToGradientType(elem.attribute("type"_L1));
168 const QGradient::Spread spread = stringToGradientSpread(elem.attribute("spread"_L1));
169 const QGradient::CoordinateMode mode = stringToGradientCoordinateMode(elem.attribute("coordinateMode"_L1));
170
171 QGradient gradient = QLinearGradient();
172
173 if (type == QGradient::LinearGradient) {
174 QLinearGradient g;
175 g.setStart(elem.attribute("startX"_L1).toDouble(), elem.attribute("startY"_L1).toDouble());
176 g.setFinalStop(elem.attribute("endX"_L1).toDouble(), elem.attribute("endY"_L1).toDouble());
177 gradient = g;
178 } else if (type == QGradient::RadialGradient) {
179 QRadialGradient g;
180 g.setCenter(elem.attribute("centerX"_L1).toDouble(), elem.attribute("centerY"_L1).toDouble());
181 g.setFocalPoint(elem.attribute("focalX"_L1).toDouble(), elem.attribute("focalY"_L1).toDouble());
182 g.setRadius(elem.attribute("radius"_L1).toDouble());
183 gradient = g;
184 } else if (type == QGradient::ConicalGradient) {
185 QConicalGradient g;
186 g.setCenter(elem.attribute("centerX"_L1).toDouble(), elem.attribute("centerY"_L1).toDouble());
187 g.setAngle(elem.attribute("angle"_L1).toDouble());
188 gradient = g;
189 }
190
191 QDomElement stopElem = elem.firstChildElement();
192 while (!stopElem.isNull()) {
193 QGradientStop stop = loadGradientStop(stopElem);
194
195 gradient.setColorAt(stop.first, stop.second);
196
197 stopElem = stopElem.nextSiblingElement();
198 }
199
200 gradient.setSpread(spread);
201 gradient.setCoordinateMode(mode);
202
203 return gradient;
204}
205
206QString QtGradientUtils::saveState(const QtGradientManager *manager)
207{
208 QDomDocument doc;
209
210 QDomElement rootElem = doc.createElement("gradients"_L1);
211
212 QMap<QString, QGradient> grads = manager->gradients();
213 for (auto itGrad = grads.cbegin(), end = grads.cend(); itGrad != end; ++itGrad) {
214 QDomElement idElem = doc.createElement("gradient"_L1);
215 idElem.setAttribute("name"_L1, itGrad.key());
216 QDomElement gradElem = saveGradient(doc, itGrad.value());
217 idElem.appendChild(gradElem);
218
219 rootElem.appendChild(idElem);
220 }
221
222 doc.appendChild(rootElem);
223
224 return doc.toString();
225}
226
227void QtGradientUtils::restoreState(QtGradientManager *manager, const QString &state)
228{
229 manager->clear();
230
231 QDomDocument doc;
232 doc.setContent(state);
233
234 QDomElement rootElem = doc.documentElement();
235
236 QDomElement gradElem = rootElem.firstChildElement();
237 while (!gradElem.isNull()) {
238 const QString name = gradElem.attribute("name"_L1);
239 const QGradient gradient = loadGradient(gradElem.firstChildElement());
240
241 manager->addGradient(name, gradient);
242 gradElem = gradElem.nextSiblingElement();
243 }
244}
245
246QPixmap QtGradientUtils::gradientPixmap(const QGradient &gradient, QSize size,
247 bool checkeredBackground)
248{
249 QImage image(size, QImage::Format_ARGB32);
250 QPainter p(&image);
251 p.setCompositionMode(QPainter::CompositionMode_Source);
252
253 if (checkeredBackground) {
254 int pixSize = 20;
255 QPixmap pm(2 * pixSize, 2 * pixSize);
256
257 QPainter pmp(&pm);
258 pmp.fillRect(0, 0, pixSize, pixSize, Qt::lightGray);
259 pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::lightGray);
260 pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::darkGray);
261 pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::darkGray);
262
263 p.setBrushOrigin((size.width() % pixSize + pixSize) / 2, (size.height() % pixSize + pixSize) / 2);
264 p.fillRect(0, 0, size.width(), size.height(), pm);
265 p.setBrushOrigin(0, 0);
266 p.setCompositionMode(QPainter::CompositionMode_SourceOver);
267 }
268
269 const qreal scaleFactor = 0.999999;
270 p.scale(scaleFactor, scaleFactor);
271 QGradient grad = gradient;
272 grad.setCoordinateMode(QGradient::StretchToDeviceMode);
273 p.fillRect(QRect(0, 0, size.width(), size.height()), grad);
274 p.drawRect(QRect(0, 0, size.width() - 1, size.height() - 1));
275
276 return QPixmap::fromImage(image);
277}
278
279static QString styleSheetFillName(const QGradient &gradient)
280{
281 QString result;
282
283 switch (gradient.type()) {
284 case QGradient::LinearGradient:
285 result += "qlineargradient"_L1;
286 break;
287 case QGradient::RadialGradient:
288 result += "qradialgradient"_L1;
289 break;
290 case QGradient::ConicalGradient:
291 result += "qconicalgradient"_L1;
292 break;
293 default:
294 qWarning() << "QtGradientUtils::styleSheetFillName(): gradient type" << gradient.type() << "not supported!";
295 break;
296 }
297
298 return result;
299}
300
301static QStringList styleSheetParameters(const QGradient &gradient)
302{
303 QStringList result;
304
305 if (gradient.type() != QGradient::ConicalGradient) {
306 QString spread;
307 switch (gradient.spread()) {
308 case QGradient::PadSpread:
309 spread = "pad"_L1;
310 break;
311 case QGradient::ReflectSpread:
312 spread = "reflect"_L1;
313 break;
314 case QGradient::RepeatSpread:
315 spread = "repeat"_L1;
316 break;
317 default:
318 qWarning() << "QtGradientUtils::styleSheetParameters(): gradient spread" << gradient.spread() << "not supported!";
319 break;
320 }
321 result << "spread:"_L1 + spread;
322 }
323
324 switch (gradient.type()) {
325 case QGradient::LinearGradient: {
326 const QLinearGradient *linearGradient = static_cast<const QLinearGradient*>(&gradient);
327 result << "x1:"_L1 + QString::number(linearGradient->start().x())
328 << "y1:"_L1 + QString::number(linearGradient->start().y())
329 << "x2:"_L1 + QString::number(linearGradient->finalStop().x())
330 << "y2:"_L1 + QString::number(linearGradient->finalStop().y());
331 break;
332 }
333 case QGradient::RadialGradient: {
334 const QRadialGradient *radialGradient = static_cast<const QRadialGradient*>(&gradient);
335 result << "cx:"_L1 + QString::number(radialGradient->center().x())
336 << "cy:"_L1 + QString::number(radialGradient->center().y())
337 << "radius:"_L1 + QString::number(radialGradient->radius())
338 << "fx:"_L1 + QString::number(radialGradient->focalPoint().x())
339 << "fy:"_L1 + QString::number(radialGradient->focalPoint().y());
340 break;
341 }
342 case QGradient::ConicalGradient: {
343 const QConicalGradient *conicalGradient = static_cast<const QConicalGradient*>(&gradient);
344 result << "cx:"_L1 + QString::number(conicalGradient->center().x())
345 << "cy:"_L1 + QString::number(conicalGradient->center().y())
346 << "angle:"_L1 + QString::number(conicalGradient->angle());
347 break;
348 }
349 default:
350 qWarning() << "QtGradientUtils::styleSheetParameters(): gradient type" << gradient.type() << "not supported!";
351 break;
352 }
353
354 return result;
355}
356
357static QStringList styleSheetStops(const QGradient &gradient)
358{
359 QStringList result;
360 const QGradientStops &stops = gradient.stops();
361 for (const QGradientStop &stop : stops) {
362 const QColor color = stop.second;
363
364 const QString stopDescription = "stop:"_L1 + QString::number(stop.first) + " rgba("_L1
365 + QString::number(color.red()) + ", "_L1
366 + QString::number(color.green()) + ", "_L1
367 + QString::number(color.blue()) + ", "_L1
368 + QString::number(color.alpha()) + QLatin1Char(')');
369 result << stopDescription;
370 }
371
372 return result;
373}
374
375QString QtGradientUtils::styleSheetCode(const QGradient &gradient)
376{
377 QStringList gradientParameters;
378 gradientParameters << styleSheetParameters(gradient) << styleSheetStops(gradient);
379
380 return styleSheetFillName(gradient) + QLatin1Char('(') + gradientParameters.join(", "_L1) + QLatin1Char(')');
381}
382
383QT_END_NAMESPACE
Combined button and popup list for selecting options.
static QString gradientSpreadToString(QGradient::Spread spread)
static QStringList styleSheetStops(const QGradient &gradient)
static QDomElement saveColor(QDomDocument &doc, QColor color)
static QGradient loadGradient(const QDomElement &elem)
static QGradient::Spread stringToGradientSpread(const QString &name)
static QString styleSheetFillName(const QGradient &gradient)
static QString gradientCoordinateModeToString(QGradient::CoordinateMode mode)
static QStringList styleSheetParameters(const QGradient &gradient)
static QColor loadColor(const QDomElement &elem)
static QGradient::Type stringToGradientType(const QString &name)
static QGradient::CoordinateMode stringToGradientCoordinateMode(const QString &name)
static QGradientStop loadGradientStop(const QDomElement &elem)
static QString gradientTypeToString(QGradient::Type type)
static QDomElement saveGradient(QDomDocument &doc, const QGradient &gradient)
static QDomElement saveGradientStop(QDomDocument &doc, const QGradientStop &stop)