1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <QtCore/qregularexpression.h>
5#include <QtGui/qbrush.h>
6#if QT_CONFIG(opengl)
7#include <QtGui/qoffscreensurface.h>
8#endif
9
10#include "private/qquickrectangle_p.h"
11#include "utils_p.h"
12
13#include <rhi/qrhi.h>
14
15QT_BEGIN_NAMESPACE
16
17static qreal s_maxTextureSize = 0.;
18
19Utils::ParamType Utils::preParseFormat(
20 const QString &format, QString &preStr, QString &postStr, int &precision, char &formatSpec)
21{
22 static QRegularExpression formatMatcher(
23 QStringLiteral("^([^%]*)%([\\-\\+#\\s\\d\\.lhjztL]*)([dicuoxfegXFEG])(.*)$"));
24 static QRegularExpression precisionMatcher(QStringLiteral("\\.(\\d+)"));
25
26 Utils::ParamType retVal;
27
28 QRegularExpressionMatch formatMatch = formatMatcher.match(subject: format, offset: 0);
29
30 if (formatMatch.hasMatch()) {
31 preStr = formatMatch.captured(nth: 1);
32 // Six and 'g' are defaults in Qt API
33 precision = 6;
34 if (!formatMatch.captured(nth: 2).isEmpty()) {
35 QRegularExpressionMatch precisionMatch = precisionMatcher.match(subject: formatMatch.captured(nth: 2),
36 offset: 0);
37 if (precisionMatch.hasMatch())
38 precision = precisionMatch.captured(nth: 1).toInt();
39 }
40 if (formatMatch.captured(nth: 3).isEmpty())
41 formatSpec = 'g';
42 else
43 formatSpec = formatMatch.captured(nth: 3).at(i: 0).toLatin1();
44 postStr = formatMatch.captured(nth: 4);
45 retVal = mapFormatCharToParamType(formatSpec);
46 } else {
47 retVal = ParamType::Unknown;
48 // The out parameters are irrelevant in unknown case
49 }
50
51 return retVal;
52}
53
54Utils::ParamType Utils::mapFormatCharToParamType(char formatSpec)
55{
56 ParamType retVal = ParamType::Unknown;
57 if (formatSpec == 'd' || formatSpec == 'i' || formatSpec == 'c') {
58 retVal = ParamType::Int;
59 } else if (formatSpec == 'u' || formatSpec == 'o' || formatSpec == 'x' || formatSpec == 'X') {
60 retVal = ParamType::UInt;
61 } else if (formatSpec == 'f' || formatSpec == 'F' || formatSpec == 'e' || formatSpec == 'E'
62 || formatSpec == 'g' || formatSpec == 'G') {
63 retVal = ParamType::Real;
64 }
65
66 return retVal;
67}
68
69QString Utils::formatLabelSprintf(const QByteArray &format, Utils::ParamType paramType, qreal value)
70{
71 switch (paramType) {
72 case ParamType::Int:
73 return QString::asprintf(format: format.constData(), qint64(value));
74 case ParamType::UInt:
75 return QString::asprintf(format: format.constData(), quint64(value));
76 case ParamType::Real:
77 return QString::asprintf(format: format.constData(), value);
78 default:
79 // Return format string to detect errors. Bars selection label logic also
80 // depends on this.
81 return QString::fromUtf8(ba: format);
82 }
83}
84
85QString Utils::formatLabelLocalized(Utils::ParamType paramType,
86 qreal value,
87 const QLocale &locale,
88 const QString &preStr,
89 const QString &postStr,
90 int precision,
91 char formatSpec,
92 const QByteArray &format)
93{
94 switch (paramType) {
95 case ParamType::Int:
96 case ParamType::UInt:
97 return preStr + locale.toString(i: qint64(value)) + postStr;
98 case ParamType::Real:
99 return preStr + locale.toString(f: value, format: formatSpec, precision) + postStr;
100 default:
101 // Return format string to detect errors. Bars selection label logic also
102 // depends on this.
103 return QString::fromUtf8(ba: format);
104 }
105}
106
107QString Utils::defaultLabelFormat()
108{
109 static const QString defaultFormat(QStringLiteral("%.2f"));
110 return defaultFormat;
111}
112
113float Utils::wrapValue(float value, float min, float max)
114{
115 if (value > max) {
116 value = min + (value - max);
117
118 // In case single wrap fails, jump to opposite end.
119 if (value > max)
120 value = min;
121 }
122
123 if (value < min) {
124 value = max + (value - min);
125
126 // In case single wrap fails, jump to opposite end.
127 if (value < min)
128 value = max;
129 }
130
131 return value;
132}
133
134QQuaternion Utils::calculateRotation(QVector3D xyzRotations)
135{
136 QQuaternion rotQuatX = QQuaternion::fromAxisAndAngle(x: 1.0f, y: 0.0f, z: 0.0f, angle: xyzRotations.x());
137 QQuaternion rotQuatY = QQuaternion::fromAxisAndAngle(x: 0.0f, y: 1.0f, z: 0.0f, angle: xyzRotations.y());
138 QQuaternion rotQuatZ = QQuaternion::fromAxisAndAngle(x: 0.0f, y: 0.0f, z: 1.0f, angle: xyzRotations.z());
139 QQuaternion totalRotation = rotQuatY * rotQuatZ * rotQuatX;
140 return totalRotation;
141}
142
143void Utils::verifyGradientCompleteness(QLinearGradient &gradient)
144{
145 // Fix the start and end stops of the gradient, to make sure it's complete
146 // (0...1)
147 auto stops = gradient.stops();
148 if (stops.first().first != 0.) {
149 const QColor firstColor = stops.first().second;
150 gradient.setColorAt(pos: 0., color: firstColor);
151 }
152 if (stops.last().first != 1.) {
153 const QColor lastColor = stops.last().second;
154 gradient.setColorAt(pos: 1., color: lastColor);
155 }
156}
157
158void Utils::setSeriesGradient(QAbstract3DSeries *series, QJSValue gradient, GradientType type)
159{
160 auto newGradient = qobject_cast<QQuickGradient *>(object: gradient.toQObject());
161 QLinearGradient linearGradient;
162 linearGradient.setStops(newGradient->gradientStops());
163
164 switch (type) {
165 case GradientType::Base:
166 series->setBaseGradient(linearGradient);
167 break;
168 case GradientType::Single:
169 series->setSingleHighlightGradient(linearGradient);
170 break;
171 case GradientType::Multi:
172 series->setMultiHighlightGradient(linearGradient);
173 break;
174 default: // Never goes here
175 break;
176 }
177}
178
179void Utils::setSeriesGradient(QAbstract3DSeries *series, QQuickGradient *gradient, GradientType type)
180{
181 QLinearGradient lg;
182 lg.setStops(gradient->gradientStops());
183 switch (type) {
184 case GradientType::Base:
185 series->setBaseGradient(lg);
186 break;
187 case GradientType::Single:
188 series->setSingleHighlightGradient(lg);
189 break;
190 case GradientType::Multi:
191 series->setMultiHighlightGradient(lg);
192 break;
193 default: // Never goes here
194 break;
195 }
196}
197
198void Utils::connectSeriesGradient(QAbstract3DSeries *series,
199 QJSValue newGradient,
200 GradientType type,
201 QJSValue &memberGradient)
202{
203 // connect new / disconnect old
204 if (newGradient.isQObject() && !newGradient.equals(other: memberGradient)) {
205 auto quickGradient = qobject_cast<QQuickGradient *>(object: memberGradient.toQObject());
206 if (quickGradient)
207 QObject::disconnect(sender: quickGradient, signal: 0, receiver: series, member: 0);
208
209 memberGradient = newGradient;
210 quickGradient = qobject_cast<QQuickGradient *>(object: memberGradient.toQObject());
211
212 const int updatedIndex = QMetaMethod::fromSignal(signal: &QQuickGradient::updated).methodIndex();
213
214 int handleIndex = -1;
215 switch (type) {
216 case GradientType::Base:
217 handleIndex = series->metaObject()->indexOfSlot(slot: "handleBaseGradientUpdate()");
218 break;
219 case GradientType::Single:
220 handleIndex = series->metaObject()->indexOfSlot(
221 slot: "handleSingleHighlightGradientUpdate()");
222 break;
223 case GradientType::Multi:
224 handleIndex = series->metaObject()->indexOfSlot(slot: "handleMultiHighlightGradientUpdate()");
225 break;
226 default: // Never goes here
227 break;
228 }
229
230 if (quickGradient)
231 QMetaObject::connect(sender: quickGradient, signal_index: updatedIndex, receiver: series, method_index: handleIndex);
232 }
233
234 if (!memberGradient.isNull())
235 setSeriesGradient(series, gradient: memberGradient, type);
236}
237
238qreal Utils::maxTextureSize()
239{
240 // Query maximum texture size only once
241 if (!s_maxTextureSize) {
242 std::unique_ptr<QRhi> rhi;
243#if defined(Q_OS_WIN)
244 QRhiD3D12InitParams params;
245 rhi.reset(QRhi::create(QRhi::D3D12, &params));
246#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
247 QRhiMetalInitParams params;
248 rhi.reset(QRhi::create(QRhi::Metal, &params));
249#elif QT_CONFIG(opengl)
250 QRhiGles2InitParams params;
251 params.fallbackSurface = QRhiGles2InitParams::newFallbackSurface();
252 rhi.reset(p: QRhi::create(impl: QRhi::OpenGLES2, params: &params));
253#elif QT_CONFIG(vulkan)
254 if (!qEnvironmentVariable("QSG_RHI_BACKEND").compare("vulkan")) {
255 QVulkanInstance inst;
256 inst.setExtensions(QRhiVulkanInitParams::preferredInstanceExtensions());
257 if (inst.create()) {
258 QRhiVulkanInitParams params;
259 params.inst = &inst;
260 rhi.reset(QRhi::create(QRhi::Vulkan, &params));
261 } else {
262 qWarning("Failed to create Vulkan instance");
263 }
264 }
265#endif
266 if (rhi)
267 s_maxTextureSize = qreal(rhi->resourceLimit(limit: QRhi::TextureSizeMax));
268 else
269 s_maxTextureSize = gradientTextureWidth;
270 }
271
272 return s_maxTextureSize;
273}
274
275QT_END_NAMESPACE
276

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtgraphs/src/graphs3d/utils/utils.cpp